工程实践:实操项目中的Docker操作

工作的时候,接触到的就不是上一篇中提到的Docker用法了,而是更复杂的镜像文件,这一篇博客就讲一下一些工程上的Docker用例。

打包项目镜像

前面其实已经提过了如何打包项目镜像,不过这里再细讲一遍:

我们的项目结构大致如下:

1
2
3
4
5
6
7
8
9
project/
|-- frontend/
| |-- Dockerfile
| |-- ... (其他前端项目文件)
|-- docker/
| |-- Dockerfile
| |-- ... (其他与Docker构建相关的文件)
|-- ... (其他项目文件)

这里,我们希望把前后端文件夹打包成镜像,以迁移到新的环境。那么我们需要再项目根目录执行以下指令:

1
2
3
4
5
cd ../frontend
docker build -t project-frontend -f Dockerfile . --no-cache

cd ../docker
docker build -t project-detector:v0.1 -f Dockerfile ../ --no-cache

解读一下上面做了什么:

  • 首先,将前端打包成镜像,使用-t命名tag为project-frontend,然后使用-f指定使用的是当前目录[frontend]的Dockerfile。
  • 然后进入docker文件夹,并使用该目录[docker]的Dockerfile构建镜像。

编写Dockerfile

什么是Dockerfile?

Dockerfile是构建镜像的蓝图。 docker pull 用于获取已有的基础镜像,docker run 用于基于镜像运行容器。

我们简单看下Dockerfile怎么写,首先是前端的Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 使用官方的 Node.js 镜像作为基础镜像
FROM node:lts-alpine as builder

# 设置环境变量,并设置为工作目录
ENV PROJECT_DIR=/project-admin
WORKDIR $PROJECT_DIR

# 安装pnpm
RUN npm install -g pnpm

# 构建项目
COPY ./ $PROJECT_DIR

# 删除.env并执行pnpm build
RUN rm -rf .env.* && pnpm build

然后是docker目录的Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 使用官方 Python 3 镜像作为基础镜像
FROM python:3.11-bookworm

COPY ./docker/debian-sources.list /etc/apt/sources.list
RUN rm -rf /etc/apt/sources.list.d/debian.sources \
&& apt-get update \
&& apt-get install -y vim \
&& apt-get install -y libgl1-mesa-glx \

COPY --from=project-frontend:latest /project-admin/dist/ /var/www/html
COPY ./docker/nginx.default.conf /etc/nginx/sites-available/default

# 设置工作目录
WORKDIR /app
# 复制当前目录下的所有文件到容器的 /app 目录
COPY ./backend /app/

# 安装项目依赖
RUN pip install -r requirements.txt

# 暴露端口号
EXPOSE 80
# 暴露python服务的端口号
EXPOSE 7091

# 执行命令行
CMD ["bash", "start.sh", "prod"]

将Docker镜像进行保存迁移

在客户无网环境的时候,无法直接使用Dockerfile来下载镜像,这时候就需要将镜像进行打包,指令如下:

1
2
3
docker save -o project-v0.1.tar project:v0.1

zip -r project-v0.1.tar.zip project-v0.1.tar

上面的指令进行了两个操作:

  • docker save: 将 Docker 镜像保存为一个 tar 归档文件。
  • -o : 指定输出文件的名称。

在打包完毕之后,就可以将zip压缩包移动至生产环境进行解压。

在生产环境解压后加载tar文件,这将在目标环境中还原,指令如下:

1
docker load -i project-v0.1.tar

使用Docker Compose启动Docker

加载完成后,就需要启动Docker,这里的代码如下:

1
docker compose -f docker-compose.service.prod.yaml up -d

这里用到了docker compose指令,该指令能够读取yaml配置文件来批量加载镜像文件,我们可以看一下这个配置文件是怎么写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
version: '3'
services:
project:
image: project
restart: always
volumes:
- /app/logs:/app/logs
- /app/captures:/app/captures
- /app/targets:/app/targets
- /app/html:/app/html
- ./envs/prod/env.prod.ini:/app/env.prod.ini
- ./envs/prod/config:/app/config
ports:
- "7901:80"

db:
image: postgres:15-alpine
restart: always
environment:
# The password for the default postgres user.
POSTGRES_PASSWORD: Fzd_1qaz2wsx
# The name of the default postgres database.
POSTGRES_DB: postgres
# postgres data directory
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./volumes/db/data:/var/lib/postgresql/data
ports:
- "52345:5432"

# The redis cache.
redis:
image: redis:6-alpine
restart: always
volumes:
# Mount the redis data directory to the container.
- ./volumes/redis/data:/data
# Set the redis password when startup redis server.
command: redis-server --requirepass Fzd_1qaz2wsx
ports:
- "56379:6379"

这里实际上是声明了不同镜像的版本和卷管理,具体解释如下:

  • version: '3': 指定 Docker Compose 文件的版本,改变它会改变Compose文件的语法。目前3是最流行的版本。
  • services: 定义了一个或多个服务。在这里,只定义了一个服务名为 “project”。
  • project: 这是服务的名称。
    • image: project:v0.1: 指定了 Docker 镜像的名称。
    • restart: always: 设置容器在退出时总是重新启动。
    • volumes: 定义了容器和主机之间的数据卷映射。这些映射用于将容器内的路径映射到主机上的相应路径。
      • /app/logs:/app/logs: 将容器内的 “/app/logs” 路径映射到主机上的 “/app/logs”,实现数据的持久化。
      • 其他类似的 volumes 条目也是为了将容器内的路径映射到主机上,以实现数据的持久化。
    • ports: 定义了容器和主机之间的端口映射。
      • "7901:80": 将容器的 80 端口映射到主机的 7901 端口。这意味着,通过访问主机的 7901 端口,可以访问容器内运行的服务的 80 端口。

2024/1/25 于苏州家中