Docker从零开始部署后端项目和MySQL数据库
预备知识
- Docker是什么
- Docker镜像是什么
- Docker容器是什么
- Docker Compose是什么
- Docker Compose中的Service是什么
请自行上网查阅以上内容相关资料,否则无法阅读下文
安装Docker
Windows
去官网Docker: Accelerated Container Application Development下载并安装。安装完成之后会提示重启。通常情况下正常重启就行。但我一开始试的那台电脑装了Windows和黑苹果双系统,在开机的时候会提示选择那个系统。结果试了好几次电脑都没法正常启动,我甚至一度以为是电脑坏了。最后进入BIOS把首选的启动选项从双系统选择器改为Windows自带的启动器,这样在重启的时候会直接进入Windows,终于成功。
docker运行的底层系统需要是Linux,Windows10之后的版本支持在Windows内运行Linux,也就是所谓的wsl。但大部分的系统本身的wsl版本太老,当你打开docker的时候也会出现提示。因此在第一次启动docker时,需要在终端执行:
wsl --update
更新wsl才行。
docker默认的镜像存储空间是在C盘,之后随着使用过程中镜像数量的增多,占据的空间会越来越大。C盘空间紧张的同学可以手动修改镜像存储空间。
点击右上角的齿轮-Resources-Advance中就可以修改镜像的默认存储位置。
Mac
同样去官网下载并安装即可,不需要执行wsl --update过程。
部署MySQL
为了简单起见,先尝试部署一个MySQL容器。MySQL已经提供了官方的镜像,直接根据该镜像创建容器即可。
执行以下命令即可部署一个最基本的MySQL容器:
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d --restart always mysql:5.7
- -p:端口映射。:左边的是宿主机(本机)端口,右边的是容器内端口。3306:3306就是将容器内的3306端口映射到宿主机的3306端口。如果本机已经部署了在本地运行的MySQL服务(默认的端口就是3306),那么就会冲突。这时候可以改成3406:3306或者任意空闲的本机端口。
- --name:这是给运行的容器起的名字,用于之后重启/停止/删除容器用
- -e:这是容器内的一些环境变量,这里设定了root用户的密码是123456
- -d:代表在后台运行容器
- --restart:代表重启Docker服务后该容器是否重启。always代表每次重启Docker服务后该容器也会重启。这样,只要设定Docker服务开机自启,那么这个MySQL容器也会开机启动,就像部署在本地的MySQL服务一样
- mysql:5.7:这是容器使用的镜像名称和标签,标签通常使用版本号来填写。mysql:5.7就代表5.7版本的MySQL镜像
启动后,尝试使用Navicat等数据库管理工具连接,用户名root,密码123456,就可以成功连接到Docker内部署的MySQL容器,之后的使用方法和本地部署的MySQL无异。
查看Docker容器
执行 docker ps
命令可以查看正在运行的Docker容器,行 docker ps -a
命令可以查看所有Docker容器,显示的信息类似下面这样
如果想要停止一个容器,可以执行 docker stop 容器ID或容器名
。容器ID就是图中的CONTAINER ID,容器名就是图中的NAMES
如果想要删除一个容器,可以执行 docker rm 容器ID或容器名
查看Docker镜像
执行 docker images
命令可以查看本地已存在的镜像。如图
如果想要删除一个镜像,首先需要确保该镜像没有被任何容器使用,即便是已经停止的容器也不行。确认完毕之后可以执行 docker rmi 镜像ID或镜像名:镜像标签
来删除。实际操作中,镜像ID可以不填完整,只要填前几个能够和其他镜像区分开来的字符即可。
部署Django后端应用
为了部署Django应用,我们需要首先打包出自己的镜像,之后再使用该镜像创建容器。
在Django项目的工作目录下,创建名为 Dockerfile
的文件,其中的内容为:
# 使用官方的 Python 镜像作为基础镜像
FROM python:3.10.4
# 设置工作目录
WORKDIR /app
# 设置 pip 使用清华源
ENV PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
# 将当前目录下的所有文件复制到工作目录
COPY . /app/
# 安装项目所需的依赖
RUN pip install -r requirements.txt
# 将容器内的端口暴露出来,这里使用 Django 默认的端口 8000
EXPOSE 8000
# 启动 Django 项目
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
之后,在同个目录下执行:
docker build -t my-django-app .
这样就可以打包出名为my-django-app的镜像。最后的 .
代表读取当前目录下的Dockerfile文件来构建镜像
之后再运行
docker run -p 8000:8000 --name django-app my-django-app
我这里没有写-d,就是为了可以看到Django的启动过程
使用docker compose同时部署后端应用和MySQL数据库,并使两者能够连接
当一个应用包含多个容器时,就需要使用Docker compose来进行组织和管理。我们安装Docker时,通常情况下默认也安装了Docker compose。
首先我们为了确保Django应用能够连上MySQL,需要去settings.py文件中修改数据库连接配置,参考以下内容:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 默认
'NAME': 'mydb', # 连接的数据库名
'HOST': 'database', # mysql的地址
'PORT': 3306, # mysql的端口
'USER': 'root', # mysql的用户名
'PASSWORD': '123456' # mysql的密码
}
}
重点就在HOST和NAME,需要和之后创建的 docker-compose.yml
中一致。HOST对应service的名称,NAME对应MYSQL_DATABASE这个环境变量。
之后创建一个 docker-compose.yml
文件,可以在任意目录下,但推荐和Dockerfile在同个目录下。
文件内容如下:
version: '3'
services:
database:
image: mysql:5.7
container_name: mysql
ports:
- "3306:3306"
volumes:
- ./mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: mydb
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
web:
image: my-django-app
container_name: django-app
command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
ports:
- "8000:8000"
depends_on:
- database
之后执行 docker-compose up -d
命令可以创建容器并运行(-d代表后台运行),在这里会同时启动Django和MySQL容器,并且可以将Django中定义的数据库模型迁移到MySQL数据库上。如果想要停止并删除上述容器,就执行 docker-compose down
命令。如果不想删除容器,只想停止,就执行 docker-compose stop
命令,之后如果又想开始,可以执行 docker-compose start
命令。
上面这个文件中有一个注意点就是在web这个service下,加了一个depends_on参数,代表该service依赖于上面的database。即首先得创建数据库容器,之后才能启动后端服务容器。
但在我的实际操作中,发现MySQL容器实际上在刚创建完成时还不能马上提供连接服务,而这个时候Docker compose以为MySQL服务已经就绪,就会启动Django服务并连接数据库,最终的结果是Django服务无法连上数据库导致启动失败。
为了避免上述情况的发生,更稳妥的方案是分别启动MySQL服务和Django服务,在确保MySQL服务就绪的情况下,再启动Django。
为此,首先需要创建一个Docker网络,并在之后将两个容器放到同一个网络下使得它们可以连接。创建网络的命令为
docker network create app_net
之后,需要创建两个docker-compose.yml文件,用于分别启动MySQL和Django。
第一个文件定义MySQL启动配置
version: '3'
networks:
custom_app_net:
name: app_net
external: true
services:
database:
image: mysql:5.7
container_name: mysql
ports:
- "3306:3306"
volumes:
- ./mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: mydb
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
networks:
- custom_app_net
执行 docker-compose up -d
命令后,确保MySQL服务启动成功后,再启动Django服务,对应的docker-compose.yml文件为:
version: '3'
networks:
custom_app_net:
name: app_net
external: true
services:
web:
image: my-django-app
container_name: django-app
command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
ports:
- "8000:8000"
depends_on:
- database
networks:
- custom_app_net
再执行 docker-compose up -d
来启动Django服务。这样就可以避免MySQL还未就绪就被Django抢连的情况。