Docker从零开始部署后端项目和MySQL数据库

2023-08-26

预备知识

  • 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中就可以修改镜像的默认存储位置。

image.png

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容器,显示的信息类似下面这样

image.png

如果想要停止一个容器,可以执行 docker stop 容器ID或容器名。容器ID就是图中的CONTAINER ID,容器名就是图中的NAMES

如果想要删除一个容器,可以执行 docker rm 容器ID或容器名

查看Docker镜像

执行 docker images命令可以查看本地已存在的镜像。如图

截屏2023082617.38.19.png

如果想要删除一个镜像,首先需要确保该镜像没有被任何容器使用,即便是已经停止的容器也不行。确认完毕之后可以执行 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抢连的情况。


标题:Docker从零开始部署后端项目和MySQL数据库
作者:aopstudio
地址:https://neusoftware.top/articles/2023/08/26/1693044908101.html