深入理解 Dockerfile 和 docker-compose[实战篇]
🏝️ 博主介绍
大家好,我是 一个搬砖的农民工,很高兴认识大家 😊 ~
👨🎓 个人介绍:本人是一名后端Java开发工程师,坐标北京 ~
🎉 感谢关注 📖 一起学习 📝 一起讨论 🌈 一起进步 ~
🙏 作者水平有限,欢迎各位大佬指正留言,相互学习进步 ~
目录
- 🏝️ 博主介绍
- 1. Dockerfile 🚀
- 🌈 1.1 Dockerfile 常用参数
- 🌈 1.2 Dockerfile 模板
- 2. docker-compose 🚀
- 🌈 2.1 docker-compose 配置文件
- 🌈 2.2 docker-compose 常用命令
- 🌈 2.3 docker-compose.yaml 配置文件模板
- 🌈 2.4 docker-compose.yaml 编排示例
- 🥝 2.4.1 环境配置
- 🥝 2.4.2 docker-compose.yaml
- 🥝 2.4.3 创建项目
- 🥝 2.4.4 启动 docker-compose.yaml
- 🥝 2.4.5 开通防火墙端口
- 🥝 2.4.6 连接到服务
- 3 构建java镜像 🚀
🌱 Dockerfile和docker-compose是Docker中两个非常重要的工具。Dockerfile提供了创建Docker镜像的手段,而docker-compose则提供了一种管理和运行多个服务的有效方法。
对于开发者来说理解并掌握这两个工具在实际工作中会有很大帮助。🍂
1. Dockerfile 🚀
Dockerfile是一个由一系列命令和参数构成的脚本,这些命令应用于基础镜像,用于创建一个新的Docker 镜像。
🌈 1.1 Dockerfile 常用参数
FROM
:指定基础镜像。
示例:FROM openjdk:17-jdk-slim。MAINTAINER(或 LABEL maintainer)
:设置镜像创建者的信息。
示例:LABEL maintainer=“John Doe”。LABEL
:除了之前提到的 LABEL maintainer,LABEL 还可以用于为镜像添加其他元数据。
示例:LABEL version=“1.0” description=“My Java application”。EXPOSE
:声明容器运行的服务端口,但并不会实际发布端口。要发布端口,需要在 docker run 时使用 -p 或 -P 参数。
示例:EXPOSE 8080。ENV
:设置环境变量
示例:ENV JAVA_HOME=/usr/local/openjdk-17。ADD
:将本地文件、目录或远程 URL 添加到容器中,并自动解压 tar 文件,可以访问网络资源。
示例:ADD myapp.jar /app/。COPY
:将本地文件或目录复制到容器中,不会解压文件,也不能访问网络资源。
示例:COPY myapp.jar /app/。RUN
:在镜像构建时执行的命令。
示例:RUN apt-get update && apt-get install -y curl。CMD
:指定容器启动时默认运行的命令,可以被docker run之后的参数替换。
示例:CMD [“java”, “-jar”, “myapp.jar”]。ENTRYPOINT
:指定容器启动时运行的命令,不会被docker run之后的参数替换。
示例:ENTRYPOINT [“java”, “-jar”]。VOLUME
:用于在容器中创建挂载点,可以链接到本地机文件系统,或者其他容器。
示例:VOLUME [“/data”]。USER
:设置运行容器时的用户名或UID
示例:USER appuser。WORKDIR
:设置工作目录,对后续的 RUN、CMD、ENTRYPOINT、ADD、COPY 等指令生效。
示例:WORKDIR /app。ONBUILD
:为镜像创建者添加触发器,当该镜像被用作另一个 Dockerfile 的基础镜像(即被 FROM 指令引用)时,这些触发器将在后续的构建步骤中执行。
示例:ONBUILD COPY . /app/src。
🌈 1.2 Dockerfile 模板
# AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性
FROM eclipse-temurin:8-jre
## 创建目录,并使用它作为工作目录
RUN mkdir -p /opt/pro_xx/jar/springboot-basis
WORKDIR /opt/pro_xx/jar/springboot-basis
## 将后端项目的 Jar 文件,复制到镜像中
COPY ./springboot-basis/springboot-basis.jar springboot-basis.jar
## 设置 TZ 时区
## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx128m"
## 暴露后端项目的 8082 端口
EXPOSE 8082
## 启动后端项目
## -Djava.security.egd=file:/dev/./urandom 是一个 Java 系统属性设置,用于指定随机数生成器的源
## /dev/urandom:这是一个非阻塞型随机数生成器
CMD java ${JAVA_OPTS} -Xms128m -Xmx128m -Djava.security.egd=file:/dev/./urandom -jar springboot-basis.jar
2. docker-compose 🚀
🌈 2.1 docker-compose 配置文件
docker-compose是一个用于定义和运行多容器Docker应用程序的工具。你可以使用YAML文件来定义应用程序的服务,然后一条命令就可以创建和启动所有的服务。
以下是一些主要的docker-compose参数:
# Docker Compose 文件版本,定义了你使用的 Compose 文件格式
version: '3.8' # 版本号,这里使用3.8,可以根据需要选择不同版本
# 定义服务,服务可以是一个或多个容器
services:
# 定义一个名为 nginx 的服务,基于 Nginx 镜像
nginx:
# 使用的镜像,可以是 Docker Hub 上的镜像或者本地构建的镜像
image: nginx:latest # 使用最新的 Nginx 镜像
# 容器启动时运行的命令,通常用于覆盖镜像默认的启动命令
command: [nginx-debug, '-g', 'daemon off;'] # 以调试模式运行 Nginx,并且前台运行以保持容器活动
# 容器内的工作目录
working_dir: /usr/share/nginx/html # Nginx 默认的网页目录
# 端口映射,格式为 "主机端口:容器端口"
ports:
- "80:80" # 将主机的 80 端口映射到容器的 80 端口
# 环境变量,用于在容器内设置环境变量
environment:
- NGINX_ROOT=/usr/share/nginx/html # 设置 Nginx 的根目录环境变量
# 挂载的卷,格式为 "主机路径:容器路径"
volumes:
- web-root:/usr/share/nginx/html # 将主机上的卷 web-root 挂载到容器的 /usr/share/nginx/html 目录
# 网络设置,定义容器加入的网络
networks:
- webnet # 将容器加入到 webnet 网络
# 部署配置,仅在使用 Docker Swarm 集群时有用
deploy:
replicas: 2 # 定义服务的副本数量为2
update_config:
parallelism: 2 # 同时更新的容器数量
delay: 10s # 每个容器更新的延迟时间
restart_policy:
condition: on-failure # 重启策略,仅在容器失败时重启
# 定义一个名为 backend 的服务,基于一个简单的 Python 应用镜像
backend:
# 构建的上下文路径和 Dockerfile 路径,用于从 Dockerfile 构建镜像
build:
context: ./ # 构建上下文是当前目录
dockerfile: Dockerfile.backend # 使用的 Dockerfile 文件名为 Dockerfile.backend
# 容器启动时运行的命令,覆盖镜像默认的启动命令
command: ["python", "app.py"] # 启动 Python 应用
# 端口映射
ports:
- "5000:5000" # 将主机的 5000 端口映射到容器的 5000 端口
# 依赖的服务,定义服务启动顺序,先启动 web 服务
depends_on:
# 在启动 backend 服务之前先启动 web 服务
- nginx # 注意:当前服务不会再依赖服务【完全启动】后启动,会在nginx服务启动一部分后就启动backend服务
# 环境变量
environment:
- FLASK_ENV=development # 设置 Flask 的环境变量为开发模式
# 网络设置
networks:
- webnet # 将容器加入到 webnet 网络
# 部署配置
deploy:
resources:
limits:
cpus: '0.50' # 限制容器使用的 CPU 资源为 0.5 个
memory: 512M # 限制容器使用的内存资源为 512MB
restart_policy:
condition: always # 重启策略,无论何种情况下都重启容器
restart: on-failure # 添加重启策略,仅在容器失败时重启
container_name: my_backend_container # 指定容器名称为 my_backend_container
env_file:
- backend.env # 从 backend.env 文件中加载环境变量
# 定义卷,用于持久化数据
volumes:
web-root: # 定义一个名为 web-root 的卷,用于存储 Nginx 的静态文件
# 定义网络,用于服务间的通信
networks:
webnet: # 定义一个名为 webnet 的网络,服务间的通信将在这个网络中进行
driver: bridge # 使用 Docker 默认的 bridge 驱动
version
:version设定docker-compose的版本,这一版本需要与Docker Engine的版本匹配services
:services定义了要创建和启动的服务集。每个服务使用一个容器。build
:构建镜像的上下文路径,你也可以通过dockerfile参数指定Dockerfile的名称和位置,或指定image直接拉取镜像运行ports
:配置端口映射,即把容器的端口映射到主机上。volumes
:定义挂载卷。可以是匿名卷、主机卷或者命名卷。environment
:设置环境变量depends_on
:定义了服务之间的依赖关系。Docker会确保依赖的服务先启动。links
:链接到其他服务。command
:重写容器启动的命令。restart
:重启策略。
no:这是默认值,表示容器不会在退出时自动重启。
always:无论容器的退出状态码是什么,都会自动重启容器。
on-failure:只有当容器的退出状态码非零时,才会自动重启容器。
unless-stopped:类似于 always,但在 Docker 守护进程停止或重启时,如果容器也被停止,则不会重启容器。env_file
:外部文件中加载环境变量,作用和environment
一样。这对于管理敏感信息(如数据库密码)特别有用,因为你可以将这些信息存储在文件中,而不是直接写在 docker-compose.yml 文件中。文件应该包含一行一个的环境变量,格式如 VAR_NAME=value。container_name
:为容器指定一个自定义的名称,而不是使用 Docker 自动生成的名称。这有助于在需要时更容易地识别和管理容器。
🌈 2.2 docker-compose 常用命令
注:docker-compose 名称必须在对应项目下面执行。
docker-compose images
:查看 Docker Compose 配置文件中定义的服务所使用的镜像。
例:docker-compose images 仅显示 Docker Compose 配置文件中定义的服务所使用的镜像。而 docker images :列出本地主机上所有已下载的 Docker 镜像,包括 docker-compose 配置中已经下载的镜像
docker-compose up
:使用 docker-compose.yml 文件启动并运行你的应用。如果服务已经存在,则默认会先停止并重新创建服务。
-f
:指定要使用的 docker-compose.yml 文件路径;
--build
:重新构建镜像;
-d
:后台运行
例:docker-compose up -d 这个命令将以分离模式(后台运行)启动并运行你的服务。
docker-compose up nginx 仅启动nginx 服务。
docker-compose down [服务ID]
:停止并删除容器,网络,网络。
例:docker-compose down --volumes 这个命令会停止你当前目录所有服务,并删除容器,网络和卷。
docker-compose pull
:拉取服务依赖的镜像。
例:docker-compose pull 这个命令会拉取 docker-compose.yml 文件中定义的服务所依赖的所有镜像。
docker-compose build
:构建或重新构建服务。
例:docker-compose build 这个命令会构建你的服务。你也可以使用 docker-compose build --no-cache 来重新构建映像。
docker-compose run
:在单个服务上运行一次性命令。
例:docker-compose run web bash 这个命令会启动 web 服务容器,并连接到 bash shell。
docker-compose exec
:在运行的容器上执行命令。
例:docker-compose exec web bash 这个命令会在运行的 web 服务容器上连接到 bash shell。
docker-compose logs
:查看容器的输出。- - tail 选项可以指定查看日志的最后几行
例:docker-compose logs -f web 这个命令会查看 web 服务的输出,-f 参数表示跟随(即实时显示日志输出)。
docker-compose ps
:列出项目中的所有容器。
例:docker-compose ps -a 这个命令会列出你的项目中正在运行的所有容器。
docker-compose config
:检查配置
例:docker-compose config 检查配置;docker-compose config -q 检查配置,有问题才输出
docker-compose start [服务ID]
:启动 docker compose 服务
例:docker-compose start 启动容器服务
docker-compose restart
:重启 docker compose 服务
例:docker-compose restart 重启容器服务
docker-compose stop
:停止 docker compose 服务
例:docker-compose stop 停止容器服务
docker-compose rm [服务ID]
:删除已经停止的服务容器。
🌈 2.3 docker-compose.yaml 配置文件模板
前提:需要安装 docker 和 docker compose
例:在 /opt 目录下新建 docker-compose.yaml 、 docker-compose.yml 、compose.yml、compose.yaml 任意一种名称文件,添加如下内容。(如果不是上面四种格式命名则需要如 mysql.yml,则需要用 docker-compose -f mysql.yml up -d
形式执行命令)
# version: '3.8' 新版本不需要指定
services:
# mysql服务
mysql:
image: mysql:5.7
container_name: mysql_container
environment:
MYSQL_ROOT_PASSWORD: root # 用户root的密码
volumes:
- ./mysql:/var/lib/mysql
ports:
- "3306:3306"
networks:
- app_network
restart: unless-stopped # 重启策略,类似于 always
# redis服务
redis:
image: redis:latest
container_name: redis_container
ports:
- "6379:6379"
volumes:
- ./redis:/data
networks:
- app_network
restart: unless-stopped
# nginx服务
nginx:
image: nginx:latest
container_name: nginx_container
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf # 需要先导入nginx.conf文件,不然会报错。因为系统创建的nginx.conf是个目录
- ./nginx/html:/usr/share/nginx/html
- ./nginx/log:/var/log/nginx
networks:
- app_network
restart: unless-stopped
# MongoDB 服务
mongo:
image: mongo:latest
container_name: mongo_container
# 用户权限目前还没弄明白,先屏蔽
# environment:
# MONGO_INITDB_ROOT_USERNAME: root
# MONGO_INITDB_ROOT_PASSWORD: 123456
# MONGO_INITDB_ROOT_ROLE: root # 赋予 root 用户最高权限
volumes:
- ./mongo:/data/db # 将 MongoDB 的数据目录映射到宿主机的 ./mongo 目录
ports:
- "27017:27017" # 将 MongoDB 的默认端口映射到宿主机的 27017 端口
networks:
- app_network
restart: unless-stopped # 重启策略
# 网络
networks:
app_network:
driver: bridge
执行 docker-compose up -d
即可下载镜像别运行服务实例
🌈 2.4 docker-compose.yaml 编排示例
🥝 2.4.1 环境配置
- docker 版本: 26.1.4
- Docker Compose 版本:v2.27.3
🥝 2.4.2 docker-compose.yaml
# version: '3.8' 新版本不需要指定
services:
# mysql服务
mysql:
image: mysql:5.7
container_name: mysql_container
environment:
MYSQL_ROOT_PASSWORD: root # 用户root的密码
volumes:
- ./mysql:/var/lib/mysql
ports:
- "3306:3306"
networks:
- app_network
restart: unless-stopped # 重启策略,类似于 always
# redis服务
redis:
image: redis:latest
container_name: redis_container
ports:
- "6379:6379"
volumes:
- ./redis:/data
networks:
- app_network
restart: unless-stopped
# nginx服务
nginx:
image: nginx:latest
container_name: nginx_container
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf # 需要先导入nginx.conf文件,不然会报错。因为系统创建的nginx.conf是个目录
- ./nginx/html:/usr/share/nginx/html
- ./nginx/log:/var/log/nginx
networks:
- app_network
restart: unless-stopped
# MongoDB 服务
mongo:
image: mongo:latest
container_name: mongo_container
environment:
MONGO_INITDB_ROOT_USERNAME: root # 可选,设置 root 用户的用户名
MONGO_INITDB_ROOT_PASSWORD: root # 可选,设置 root 用户的密码
volumes:
- ./mongo:/data/db # 将 MongoDB 的数据目录映射到宿主机的 ./mongo 目录
ports:
- "27017:27017" # 将 MongoDB 的默认端口映射到宿主机的 27017 端口
networks:
- app_network
restart: unless-stopped # 重启策略
# 网络
networks:
app_network:
driver: bridge
🥝 2.4.3 创建项目
[root@localhost opt]# mkdir pro_xx
[root@localhost opt]# cd pro_xx
[root@localhost pro_xx]# mkdir nginx
在pro_xx目录下导入 docker-compose.yaml 文件
在pro_xx/nginx下导入 nginx.conf 文件
# nginx.conf模板
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
🥝 2.4.4 启动 docker-compose.yaml
回到 pro_xx 目录,执行 docker-compose up -d
启动服务,docker-compose ps 查看服务是否启动成功
[root@localhost pro_xx]# docker-compose up -d
[+] Running 4/4
✔ Network pro_xx_app_network Created 0.1s
✔ Container mysql_container Started 0.5s
✔ Container redis_container Started 0.5s
✔ Container nginx_container Started 0.5s
[root@localhost pro_xx]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
mysql_container mysql:5.7 "docker-entrypoint.s…" db 21 seconds ago Up 19 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp
nginx_container nginx:latest "/docker-entrypoint.…" nginx 21 seconds ago Up 19 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp
redis_container redis:latest "docker-entrypoint.s…" redis 21 seconds ago Up 19 seconds 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp
docker-compose logs 可以查看服务运行日志:
[root@localhost pro_xx]# docker-compose logs
...
mysql_container | 2024-10-12T19:59:52.758021Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
mysql_container | 2024-10-12T19:59:52.758070Z 0 [Note] IPv6 is available.
mysql_container | 2024-10-12T19:59:52.758088Z 0 [Note] - '::' resolves to '::';
nginx_container | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx_container | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx_container | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx_container | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx_container | 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
nginx_container | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
nginx_container | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx_container | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx_container | /docker-entrypoint.sh: Configuration complete; ready for start up
mysql_container | 2024-10-12T19:59:52.758109Z 0 [Note] Server socket created on IP: '::'.
mysql_container | 2024-10-12T19:59:52.758780Z 0 [Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
mysql_container | 2024-10-12T19:59:52.763935Z 0 [Note] Event Scheduler: Loaded 0 events
mysql_container | 2024-10-12T19:59:52.764089Z 0 [Note] mysqld: ready for connections.
mysql_container | Version: '5.7.44' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
验证mysql是否启动成功:
[root@localhost pro_xx]# docker-compose exec db bash
bash-4.2# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.44 MySQL Community Server (GPL)
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
🥝 2.4.5 开通防火墙端口
⚡ 推荐参考:CentOS 系统如何在防火墙开启端口
sudo firewall-cmd --zone=public --permanent --add-port=3306/tcp
sudo firewall-cmd --zone=public --permanent --add-port=6379/tcp
sudo firewall-cmd --zone=public --permanent --add-port=80/tcp
sudo firewall-cmd --zone=public --permanent --add-port=443/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-ports
🥝 2.4.6 连接到服务
电脑通过cmd打开命令提示符,运行下面指令能正常访问mysql和redis则说明防火墙开通成功。192.168.159.128为虚拟机ip
C:\Users>redis-cli -h 192.168.159.128 -p 6379
192.168.159.128:6379> keys *
(empty list or set)
192.168.159.128:6379> ^C
C:\Users>mysql -h 192.168.159.128 -u root -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.44 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
3 构建java镜像 🚀
⚡ 推荐参考:Dockerfile + docker-compose 构建java镜像并运行服务