Appearance
Docker 容器
虚拟机与容器对比
虚拟机 | 容器 | |
---|---|---|
优点 | - 使用简单 - 有成熟管理工具,如 VMware - 可以随意定制 | - 快速部署 - 大部分环境都有现成镜像 - 让我们不再关注系统基础设施,把关注点放在配置、升级、优化 - 不依赖硬件 - 相当于一个进程 |
缺点 | - 需要硬件支持虚拟化技术 - 资源利用率不高 - 同一台虚拟机跑多个服务,可能有冲突 - 占用资源较多 - 不满足目前升级、快速扩容、快速部署,回滚不方便 | - 使用较为复杂 - 共享 Linux 系统内核,推荐使用较新 Linux 内核 |
本地安装 Docker 并运行 Nginx 测试
环境准备
bash
[root@docker01.oldboylinux.cn ~]# rz -E
rz waiting to receive.
[root@docker01.oldboylinux.cn ~]# ll
总用量 72104
-rw------- 1 root root 3208 2月 20 11:39 anaconda-ks.cfg
-rw-r--r-- 1 root root 73823487 3月 18 12:11 docker-27.0.3.tgz
-rw-r--r-- 1 root root 3779 2月 20 14:56 initial-setup-ks.cfg
[root@docker01.oldboylinux.cn ~]# ll docker-27.0.3.tgz
-rw-r--r-- 1 root root 73823487 3月 18 12:11 docker-27.0.3.tgz
[root@docker01.oldboylinux.cn ~]# tar -xzvf docker-27.0.3.tgz
docker/
docker/docker-init
docker/runc
docker/containerd-shim-runc-v2
docker/ctr
docker/docker
docker/dockerd
docker/containerd
docker/docker-proxy
[root@docker01.oldboylinux.cn ~]# ll
总用量 72104
-rw------- 1 root root 3208 2月 20 11:39 anaconda-ks.cfg
drwxrwxr-x 2 oldboy oldboy 146 6月 29 2024 docker
-rw-r--r-- 1 root root 73823487 3月 18 12:11 docker-27.0.3.tgz
-rw-r--r-- 1 root root 3779 2月 20 14:56 initial-setup-ks.cfg
[root@docker01.oldboylinux.cn ~]# chown root.root docker/*
[root@docker01.oldboylinux.cn ~]# ll docker
总用量 194132
-rwxr-xr-x 1 root root 39161856 6月 29 2024 containerd
-rwxr-xr-x 1 root root 12496896 6月 29 2024 containerd-shim-runc-v2
-rwxr-xr-x 1 root root 19361792 6月 29 2024 ctr
-rwxr-xr-x 1 root root 38498840 6月 29 2024 docker
-rwxr-xr-x 1 root root 71298872 6月 29 2024 dockerd
-rwxr-xr-x 1 root root 708448 6月 29 2024 docker-init
-rwxr-xr-x 1 root root 1979949 6月 29 2024 docker-proxy
-rwxr-xr-x 1 root root 15275560 6月 29 2024 runc
[root@docker01.oldboylinux.cn ~]# mv docker/* /bin/
[root@docker01.oldboylinux.cn ~]# rz -E
rz waiting to receive.
[root@docker01.oldboylinux.cn ~]# mv docker.service /usr/lib/systemd/system
[root@docker01.oldboylinux.cn ~]# systemctl daemon-reload
[root@docker01.oldboylinux.cn ~]# systemctl start docker
[root@docker01.oldboylinux.cn ~]# systemctl enable docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[root@docker01.oldboylinux.cn ~]# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2025-03-18 12:17:27 CST; 11s ago
Docs: https://docs.docker.com
Main PID: 1371 (dockerd)
Tasks: 17
Memory: 36.1M
CGroup: /system.slice/docker.service
├─1371 /usr/bin/dockerd
└─1378 containerd --config /var/run/docker/containerd/containerd.toml
导入常用镜像 Nginx 并运行
1. 解压镜像文件
bash
tar -xzvf oldboyedu_useful_docker_images.tar.gz
解压后,你应该会得到一个目录 oldboyedu_useful_docker_images
,其中存放多个 .tar
结尾的 Docker 镜像文件。
2. 查看本地已有的 Docker 镜像
bash
docker images
这个命令会列出你当前系统中的所有 Docker 镜像。
3. 进入解压后的目录
bash
cd oldboyedu_useful_docker_images
4. 导入所有 .tar
结尾的镜像文件
bash
for n in `ls *.tar`
do
docker load -i $n
done
解释:
ls *.tar
获取当前目录下所有.tar
结尾的 Docker 镜像文件。for
循环遍历每个.tar
文件,并使用docker load -i
逐个导入到 Docker 中。
5. 确认镜像导入成功
bash
[root@docker01.oldboylinux.cn ~/oldboyedu_useful_docker_images]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0-jdk8 56d6933de864 20 months ago 285MB
nginx 1.24 b6c621311b44 20 months ago 142MB
mysql 5.7-debian b5d7c63fe339 20 months ago 463MB
mysql 8.0-debian 5557a1823e30 20 months ago 602MB
debian buster 1de12428f6f4 20 months ago 114MB
debian bullseye 189a2f977ff1 20 months ago 124MB
debian bookworm 3676c78a12ad 20 months ago 116MB
ubuntu 20.04 14be0685b768 20 months ago 72.8MB
ubuntu 22.04 5a81c4b8502e 20 months ago 77.8MB
nginx 1.24-alpine 55ba84d7d539 21 months ago 41.1MB
redis 6.0-alpine 26c28490dc59 21 months ago 26.6MB
alpine latest c1aabb73d233 21 months ago 7.33MB
php 7-fpm 38f2b691dcb8 2 years ago 443MB
redis 5.0-alpine 7558bc54e8a2 2 years ago 22.9MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
redis 4.0-alpine e3dd0e49bca5 4 years ago 20.4MB
java 8u111-jdk d23bdf5b1b1b 8 years ago 643MB
6. 删除已麒麟自带的 Docker 环境
bash
rm -f /usr/local/bin/runc
7. 开启内核转发
bash
root@docker01.oldboylinux.cn ~/oldboyedu_useful_docker_images]# sysctl -p
kernel.sysrq = 0
net.ipv4.ip_forward = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_syncookies = 1
kernel.dmesg_restrict = 1
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
8. 运行
bash
docker run -d --name ngx_test -p 80:80 nginx:1.24
浏览器访问宿主机 ip:80 ---->容器中 80
bash
docker run -d --name ngx_test2 -p 81:80 nginx:1.24
浏览器访问宿主机 ip:81---->容器中 80
解释:
docker run
启动一个新的 Docker 容器。-d
后台运行(Detached mode),容器启动后不会占据终端,会在后台运行。如果不加-d
,那么 Nginx 容器会在前台运行,显示 Nginx 访问日志等信息。--name ngx_test2
自定义容器名称,这里把容器命名为ngx_test2
。如果不指定--name
,Docker 会自动分配一个随机名称。-p 81:80
端口映射,将宿主机的 81 端口映射到容器的 80 端口,格式为:-p 宿主机端口:容器端口
。宿主机访问http://localhost:81
,等同于访问容器的http://localhost:80
。nginx 服务器默认监听 80 端口,因此把宿主机的 81 端口映射过去。nginx:1.24
指定使用nginx:1.24
版本的镜像。如果本地没有这个镜像,Docker 会自动从 Docker Hub 拉取。
9. 检查是否运行
bash
docker ps -a # 查看所有
docker ps # 查看运行
Docker 镜像指令
镜像
查看镜像
bash
docker images 或 docker image ls
下载镜像
bash
docker pull nginx:latest # 避免使用latest标签,建议使用具体版本号
删除镜像
bash
docker image rm 或 docker rmi # 镜像在使用中时,需先删除容器
导出镜像
bash
docker save nginx:1.24 -o nginx.tar 或 docker save nginx:1.24 | gzip > nginx.tar.gz
导入镜像
bash
docker load -i xxx.tar 或 docker load -i xxx.tar.gz
load 导入示例:
bash
[root@docker01.oldboylinux.cn ~]# docker save nginx:1.24 -o nginx.tar
[root@docker01.oldboylinux.cn ~]# ll
-rw------- 1 root root 146628096 3月 19 10:08 nginx.tar
[root@docker01.oldboylinux.cn ~]# scp nginx.tar 10.0.0.82:/root/
[root@docker02.oldboylinux.cn ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
[root@docker02.oldboylinux.cn ~]# docker load -i nginx.tar
4b3ba104e9a8: Loading layer 84.03MB/84.03MB
6310117db5a7: Loading layer 62.55MB/62.55MB
e543857b2aef: Loading layer 3.584kB/3.584kB
629fd7b81c65: Loading layer 4.608kB/4.608kB
0b27f1638f81: Loading layer 3.584kB/3.584kB
f62590d48fe5: Loading layer 7.168kB/7.168kB
Loaded image: nginx:1.24
[root@docker02.oldboylinux.cn ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.24 b6c621311b44 20 months ago 142MB
镜像标签
bash
docker tag 原有的名字 新名字 或 docker tag 镜像id 新名字
查看镜像详细信息
bash
docker inspect 镜像
docker inspect nginx:1.24
docker inspect mysql:8.0-debian
bash
[root@docker01.oldboylinux.cn ~]# yum -y install jq
[root@docker01.oldboylinux.cn ~]# docker inspect nginx:1.24
[root@docker01.oldboylinux.cn ~]# docker inspect mysql:8.0-debian | jq .[].RepoTags
[
"mysql:8.0-debian"
]
[root@docker01.oldboylinux.cn ~]# docker inspect mysql:8.0-debian | jq .[].RepoTags|jq .[]
"mysql:8.0-debian"
镜像命令总结集合
镜像操作命令 | 选项 | 例子 |
---|---|---|
docker images | -a 查看所有镜像(包括中间层镜像) | docker images -a |
docker pull | <镜像名>:<标签> 指定镜像名和标签 | docker pull ubuntu:latest |
docker rmi | <镜像ID或镜像名> 指定要删除的镜像 | docker rmi abcdef123456 或 docker rmi ubuntu:latest |
docker inspect | <资源ID或资源名> 指定要查看的资源 | docker inspect abcdef123456 (查看容器信息,替换为容器ID)或 docker inspect ubuntu:latest (查看镜像信息) |
docker save | -o <导出文件名> 指定导出文件的名称 | docker save -o ubuntu_latest.tar ubuntu:latest |
docker load | <导入文件名> 指定要导入的文件 | docker load < ubuntu_latest.tar |
tag | 通常作为 docker 命令的子命令,如 docker tag | docker tag ubuntu:latest myubuntu:latest (给镜像打新标签) |
build | -t <镜像名>:<标签> 指定构建后的镜像名和标签 | docker build -t myapp:latest . (在当前目录下构建镜像) |
history | <镜像名或镜像ID> 查看镜像的构建历史 |
Docker 容器指令
获取帮助
bash
docker container help
运行容器
bash
docker run
导出容器
docker export
用于将正在运行或已停止的容器导出为一个 tar 压缩文件,以便备份或迁移。
bash
docker export -o 文件名.tar 容器ID或容器名称
导入为镜像
docker import
用于将一个 tar 文件(通常是 docker export
生成的文件)导入为一个新的 Docker 镜像。
bash
docker import 文件名.tar 镜像名:标签
查看容器详细信息
bash
docker inspect 容器
示例:
bash
docker inspect ngx_test
[root@docker01.oldboylinux.cn ~]# docker inspect ngx_test | jq '.[0].Config.Env'
[
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.24.0",
"NJS_VERSION=0.7.12",
"PKG_RELEASE=1~bullseye"
]
进入已经运行的容器
bash
docker exec -it 容器名字 /bin/bash
Docker 启动 Nginx
bash
[root@docker01.oldboylinux.cn ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fa112253fb8e nginx:1.24-alpine "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:81->80/tcp, :::81->80/tcp ngx_alpine
15be80e3072a nginx:1.24 "/docker-entrypoint.…" 21 hours ago Exited (255) 13 hours ago 0.0.0.0:80->80/tcp, :::80->80/tcp ngx_test
[root@docker01.oldboylinux.cn ~]# docker start 15be80e3072a
15be80e3072a
[root@docker01.oldboylinux.cn ~]# docker exec -it ngx_test /bin/bash
# echo "Test nginx">/usr/share/nginx/html/index.html
[root@docker01.oldboylinux.cn ~]# docker exec -it ngx_alpine /bin/sh
/ # echo "NGINX-alpine" > /usr/share/nginx/html/index.html
Docker 启动 MySQL 查看日志解决问题
bash
[root@docker01.oldboylinux.cn ~]# docker run -d --name mysql_test mysql:8.0-debian
feae8dd0c85e469c9a525fef47b2c263a2f5eddc434811325782efc191370d9d
[root@docker01.oldboylinux.cn ~]# docker exec -it mysql_test /bin/bash/
Error response from daemon: container feae8dd0c85e469c9a525fef47b2c263a2f5eddc434811325782efc191370d9d is not running
# 数据库未运行
[root@docker01.oldboylinux.cn ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
feae8dd0c85e mysql:8.0-debian "docker-entrypoint.s…" 49 seconds ago Exited (1) 43 seconds ago mysql_test
fa112253fb8e nginx:1.24-alpine "/docker-entrypoint.…" 34 minutes ago Up 34 minutes 0.0.0.0:81->80/tcp, :::81->80/tcp ngx_alpine
15be80e3072a nginx:1.24 "/docker-entrypoint.…" 21 hours ago Up 29 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp ngx_test
[root@docker01.oldboylinux.cn ~]# docker logs mysql_test
2025-03-19 04:03:07+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.33-1debian11 started.
2025-03-19 04:03:10+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2025-03-19 04:03:10+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.33-1debian11 started.
2025-03-19 04:03:10+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
You need to specify one of the following as an environment variable:
- MYSQL_ROOT_PASSWORD
- MYSQL_ALLOW_EMPTY_PASSWORD
- MYSQL_RANDOM_ROOT_PASSWORD
# 缺少环境变量
[root@docker01.oldboylinux.cn ~]# docker rm mysql_test
# -e MYSQL_ROOT_PASSWORD=1:通过 -e 参数设置容器环境变量。
# 这个例子中,MYSQL_ROOT_PASSWORD=1 设置了 MySQL 容器的 root 用户密码为 1。
[root@docker01.oldboylinux.cn ~]# docker run -d --name mysql_test -e MYSQL_ROOT_PASSWORD=1 mysql:8.0-debian
b8c6070141c8e7ce34fb0b27247eb673247e7483a665d1be9b2c83200576bc6d
# 进入数据库 成功
[root@docker01.oldboylinux.cn ~]# docker exec -it mysql_test mysql -uroot -p1
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.33 MySQL Community Server - GPL
Docker 启动系统容器
bash
docker run -itd --name debian_test2 debian:bullseye /bin/bash
run
命令用于创建并运行一个新的容器-itd
(三个选项的组合):-i
(interactive):保持标准输入(STDIN)打开,即使容器没有附加到终端,这样可以确保容器不会立即退出。-t
(tty):分配一个伪终端(TTY),让你可以使用 bash 或其他交互式命令。-d
(detach):让容器在后台运行,不会占用你的终端。
📌 -itd 的作用:
-it
使得容器能够进行交互,适用于 bash 这样的 Shell 终端。-d
让容器在后台运行,否则-it
会让你直接进入容器。
示例:
bash
[root@docker01.oldboylinux.cn ~]# docker run -itd --name ngx_test05 nginx:1.24 /bin/bash
e8fcbeb35716c78cd3f81b0fc085c412bc2950ba12a830eddad3d77eaf470cb2
[root@docker01.oldboylinux.cn ~]# docker exec -itd ngx_test05 /bin/bash
[root@docker01.oldboylinux.cn ~]# docker exec -it ngx_test05 /bin/bash
# nginx 检查
root@e8fcbeb35716:/# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# 手动启动Nginx
root@e8fcbeb35716:/# nginx
2025/03/19 06:54:54 [notice] 20#20: using the "epoll" event method
2025/03/19 06:54:54 [notice] 20#20: nginx/1.24.0
2025/03/19 06:54:54 [notice] 20#20: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2025/03/19 06:54:54 [notice] 20#20: OS: Linux 4.19.90-52.22.v2207.ky10.x86_64
2025/03/19 06:54:54 [notice] 20#20: getrlimit(RLIMIT_NOFILE): 1048576:1048576
root@e8fcbeb35716:/# 2025/03/19 06:54:54 [notice] 21#21: start worker processes
2025/03/19 06:54:54 [notice] 21#21: start worker process 22
2025/03/19 06:54:54 [notice] 21#21: start worker process 23
阻塞问题
GPT 解释:
在 Docker 中,容器的生命周期是由容器内的主进程(PID 1)的生命周期决定的。简单来说,当你启动一个容器时,Docker 会运行你指定的主进程;如果这个进程退出,容器就会自动停止运行。
详细解释:
- 主进程与容器生命周期:Docker 容器内部只有一个主进程(通常是你在 Dockerfile 中通过 CMD 或 ENTRYPOINT 指定的命令),Docker 会监控这个进程的状态。如果主进程结束,Docker 认为容器的任务已经完成,因此容器就会退出。
- 阻塞进程的重要性:为了让容器保持运行,你需要确保主进程能够持续运行并“阻塞”住容器。例如,运行一个 Web 服务器(如 nginx 或 Apache)时,服务器会持续监听请求,这个过程不会退出,从而使容器一直处于运行状态。如果你的进程在启动后很快结束(例如执行一个短暂的脚本),容器就会随之退出。
常见做法:
- 前台运行服务:确保服务以非守护方式在前台运行。例如,很多应用程序都提供选项让它们在前台运行,这样 Docker 就能正确地管理它们的生命周期。
- 保持进程阻塞:在某些场景下,可以使用诸如
tail -f /dev/null
的方式保持容器前台阻塞,防止容器立即退出(不过这种方法一般只适用于调试或临时用途)。
总结:
Docker 启动时会等待容器内的主进程一直运行,这就是所谓的“启动阻塞”。只要这个进程不退出,容器就会保持运行状态;一旦该进程结束,容器也就随之终止。理解这一点对于编写 Dockerfile 和设计容器化应用非常关键,因为这直接影响到容器的稳定性和可用性。
查看容器状态指令
Docker stats
bash
[root@docker01.oldboylinux.cn ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e8fcbeb35716 ngx_test05 0.00% 3.023MiB / 3.816GiB 0.08% 1.08kB / 0B 4.1kB / 0B 5
011e1005b6d7 debian_test2 0.00% 492KiB / 3.816GiB 0.01% 1.08kB / 0B 1.19MB / 0B 1
b8c6070141c8 mysql_test 0.51% 404.4MiB / 3.816GiB 10.35% 1.29kB / 0B 43.2MB / 265MB 38
fa112253fb8e ngx_alpine 0.00% 2.164MiB / 3.816GiB 0.06% 7.46kB / 4.29kB 926kB / 7.17kB 3
15be80e3072a ngx_test 0.00% 10.47MiB / 3.816GiB 0.27% 29.5kB / 11.5kB 13.6MB / 16.4kB 3
动态修改正在运行的容器的资源限制
动态修改正在运行的容器的资源限制,比如 CPU、内存、重启策略等,而无需重启容器。
bash
[root@docker01.oldboylinux.cn ~]# docker update -m 1024m --memory-swap 1024m mysql_test
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e8fcbeb35716 ngx_test05 0.00% 3.023MiB / 3.816GiB 0.08% 1.08kB / 0B 4.1kB / 0B 5
011e1005b6d7 debian_test2 0.00% 492KiB / 3.816GiB 0.01% 1.08kB / 0B 1.19MB / 0B 1
b8c6070141c8 mysql_test 0.48% 404.4MiB / 1GiB 39.49% 1.29kB / 0B 43.2MB / 265MB 38
修改容器重启策略
bash
docker update --restart=always test22
让 test22
容器始终自动重启。
可用策略:
no
:不自动重启always
:总是重启unless-stopped
:除非手动停止,否则会自动重启on-failure
:仅在非 0 退出码时才重启
示例:
bash
[root@docker01.oldboylinux.cn ~]# docker ps -a | awk 'NR>1{print $NF}'| xargs docker update --restart always
ngx_test05
debian_test2
mysql_test
ngx_alpine
ngx_test
Docker top 查看指定容器,相当于 Linux ps 命令
-L
选项表示显示线程信息,即一个进程中的所有线程都会被列出。
bash
[root@docker01.oldboylinux.cn ~]# docker top ngx_test -efL
UID PID PPID LWP C NLWP STIME TTY TIME CMD
root 3131 3110 3131 0 1 11:34 ? 00:00:00 nginx: master process nginx -g daemon off;
101 3164 3131 3164 0 1 11:34 ? 00:00:00 nginx: worker process
101 3165 3131 3165 0 1 11:34 ? 00:00:00 nginx: worker process
[root@docker01.oldboylinux.cn ~]# docker top ngx_test -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 3131 0.0 0.1 8932 5428 ? Ss 11:34 0:00 nginx: master process nginx -g daemon off;
101 3164 0.0 0.0 9352 2612 ? S 11:34 0:00 nginx: worker process
101 3165 0.0 0.0 9352 2612 ? S 11:34 0:00 nginx: worker process
[root@docker01.oldboylinux.cn ~]# docker top ngx_test -ef
UID PID PPID C STIME TTY TIME CMD
root 3131 3110 0 11:34 ? 00:00:00 nginx: master process nginx -g daemon off;
101 3164 3131 0 11:34 ? 00:00:00 nginx: worker process
101 3165 3131 0 11:34 ? 00:00:00 nginx: worker process
创建自定义镜像 Commit
bash
[root@docker01.oldboylinux.cn ~]# docker ps -aq
e8fcbeb35716
011e1005b6d7
b8c6070141c8
fa112253fb8e
15be80e3072a
[root@docker01.oldboylinux.cn ~]# docker ps -aq|xargs docker rm -f
e8fcbeb35716
011e1005b6d7
b8c6070141c8
fa112253fb8e
15be80e3072a
[root@docker01.oldboylinux.cn ~]# docker run -d --name ngx_test -p 8080:80 nginx:1.24
6211918fca3801462a7b9a72976f4af68f78b1c07db636b7769cabf21d3d428d
# 两个窗口操作
[root@docker01.oldboylinux.cn ~]# docker exec -it ngx_test /bin/bash
root@6211918fca38:/#
# cp宿主机与容器传输数据
[root@docker01.oldboylinux.cn ~]# docker cp bird.tar.gz ngx_test:/tmp/
Successfully copied 93.2kB to ngx_test:/tmp/
# 建议Tar有的时候zip没有命令
root@6211918fca38:/# tar -xf /tmp/bird.tar.gz -C /usr/share/nginx/html/
root@6211918fca38:/# egrep -v '^$|#' /etc/nginx/conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# 在宿主机修改defaut
server {
listen 80;
listen [::]:80;
server_name localhost;
root /usr/share/nginx/html;
location / {
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~* \.(html|css|js|png)$ {
expires 7d;
}
}
# 宿主机传过去
[root@docker01.oldboylinux.cn ~]# docker cp default.conf ngx_test:/etc/nginx/conf.d/
Successfully copied 2.05kB to ngx_test:/etc/nginx/conf.d/
# 容器检查语法
nginx -t
# 重启容器服务
[root@docker01.oldboylinux.cn ~]# docker restart ngx_test
ngx_test
[root@docker01.oldboylinux.cn ~]# docker commit ngx_test web:version01
sha256:4511318f044545225cdeba46bc927c4d6bb49f4990cfef4a956b8123c77859a7
[root@docker01.oldboylinux.cn ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web version01 4511318f0445 12 seconds ago 142MB
[root@docker01.oldboylinux.cn ~]# docker run -d --name final_bird -p 80:80 web:version01
0d2db50339e2d60f24085d6f920159e54f8df6e8577d5537594d968f85b3c7e3
[root@docker01.oldboylinux.cn ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d2db50339e2 web:version01 "/docker-entrypoint.…" 2 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp final_bird
# 测试
curl 10.0.0.81
容器端口映射
docker run -p
背后发生什么?
当你执行类似 docker run -p 8080:80
的命令时,Docker 会在后台完成以下几步:
1. 容器网络隔离与网络命名空间
Docker 启动容器时,会为它创建独立的网络命名空间,这意味着容器拥有独立的 IP 地址、端口空间以及自己的网络堆栈。
2. 虚拟网络接口对接
Docker 为容器创建一对虚拟以太网设备(veth pair),一端进入容器的网络命名空间(容器内的网络接口),另一端连接到宿主机上的默认虚拟桥接网络(通常是 docker0)。
3. 端口映射的实现(iptables 规则配置)
当使用 -p
参数时,Docker 会在宿主机上选择一个端口(如8080),并建立 iptables 规则:
- DNAT(目的地址转换):在 PREROUTING 链中设置规则,把发往宿主机 8080 端口的流量转发(DNAT)到容器内对应的 IP 地址及端口(例如 172.17.0.X:80)。
- SNAT/MASQUERADE:对于容器对外发出的数据包,Docker 在 POSTROUTING 链中使用 MASQUERADE 规则,把容器内的源地址转换成宿主机的 IP 地址,确保返回数据能正确路由回容器。
4. 透明转发
这样,当外部访问宿主机的 8080 端口时,iptables 会将流量重定向到容器的 80 端口,整个过程对用户是透明的。
iptables 端口映射与共享上网流程原理
iptables 在实现 NAT 与端口映射时,主要分为以下两大部分:
端口映射(DNAT)
- 工作链:PREROUTING
当外部数据包到达宿主机时,iptables 的 PREROUTING 链会首先检查是否有 DNAT 规则匹配。例如,一条规则会把目的端口为 8080 的数据包重定向到容器内某个 IP 的 80 端口。
过程概览:
- 外部客户端发起请求,目标地址为宿主机的公网 IP,端口为 8080。
- PREROUTING 规则匹配到该数据包后,将目标地址改为容器 IP,目标端口改为 80。
- 数据包随后通过正常路由,进入容器的网络命名空间,交由容器内的服务处理。
共享上网(SNAT/MASQUERADE)
- 工作链:POSTROUTING
当容器发出数据包到外部网络时,数据包原本的源地址是容器的私有 IP,这个地址在公网中不可达。为了解决这个问题,iptables 在 POSTROUTING 链中应用 SNAT 或 MASQUERADE 规则:
过程概览:
- 容器发起外部请求,源地址为容器 IP。
- POSTROUTING 规则将数据包的源地址替换为宿主机的公网 IP(通常通过 MASQUERADE 动态实现)。
- 数据包离开宿主机时使用转换后的源地址,从而使响应数据包能正确返回。
流程总结
- 入站流量:
- 外部请求 → 经过 PREROUTING 的 DNAT 规则(端口映射) → 路由到容器内服务。
- 出站流量:
- 容器请求 → 经过 POSTROUTING 的 MASQUERADE 规则(SNAT) → 数据包的源地址改为宿主机 IP → 发送到互联网。
这种机制不仅实现了外部访问容器(端口映射),同时也使得容器内的应用能够共享上网,正常访问外部互联网。
数据卷
数据卷挂载 -v
Docker 数据卷(Volume)是用于持久化数据的一种机制,可以在容器销毁后仍然保留数据。主要用于存储数据库数据、日志文件、配置文件等。容器本质上是临时的,如果容器被删除,里面的数据也会丢失。
为了解决这个问题,可以使用数据卷(Volume)或者绑定挂载(Bind Mounts)来让数据持久化存储。
-v
实现宿主机和容器的映射
挂载数据库的目录:
bash
[root@docker02.oldboylinux.cn /test]# docker run -d -p 3306:3306 --name mysql --restart always -e MYSQL_ROOT_PASSWORD=1 mysql:8.0-debian
34c7978aae6ae4386a814b67f601ccd079b54c2b67f493c8353f98fa0f3c9bad
查看进程
bash
[root@docker02.oldboylinux.cn /test]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34c7978aae6a mysql:8.0-debian "docker-entrypoint.s…" 39 seconds ago Up 38 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql
21594ed41fd0 test01 "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:80-81->80-81/tcp, :::80-81->80-81/tcp, 443/tcp test01
查看日志是否成功
bash
[root@docker02.oldboylinux.cn /test]# docker logs mysql
2025-03-20T09:25:44.477023Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.33' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
2025-03-20T09:25:44.477026Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
创建数据库测试
bash
[root@docker02.oldboylinux.cn /test]# docker exec -it mysql mysql -uroot -p1
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.05 sec)
删除容器
bash
[root@docker02.oldboylinux.cn /test]# docker rm -f mysql
mysql
重新运行容器并挂载数据卷
bash
[root@docker02.oldboylinux.cn /test]# docker run -d -p 3306:3306 --name db --restart always -e MYSQL_ROOT_PASSWORD=1 -v /app/mysql/data/:/var/lib/mysql/ mysql:8.0-debian
996a1a01e75c43ae3140c2a86cef56644e1185366f42b9f65fa654392918deb0
查看挂载目录
bash
[root@docker02.oldboylinux.cn /app/mysql/data]# ll
总用量 99636
-rw-r----- 1 systemd-coredump input 56 3月 20 19:28 auto.cnf
-rw-r----- 1 systemd-coredump input 2994206 3月 20 19:28 binlog.000001
-rw-r----- 1 systemd-coredump input 157 3月 20 19:28 binlog.000002
-rw-r----- 1 systemd-coredump input 32 3月 20 19:28 binlog.index
-rw------- 1 systemd-coredump input 1680 3月 20 19:28 ca-key.pem
-rw-r--r-- 1 systemd-coredump input 1112 3月 20 19:28 ca.pem
-rw-r--r-- 1 systemd-coredump input 1112 3月 20 19:28 client-cert.pem
-rw------- 1 systemd-coredump input 1676 3月 20 19:28 client-key.pem
-rw-r----- 1 systemd-coredump input 196608 3月 20 19:28 '#ib_16384_0.dblwr'
-rw-r----- 1 systemd-coredump input 8585216 3月 20 19:28 '#ib_16384_1.dblwr'
-rw-r----- 1 systemd-coredump input 5657 3月 20 19:28 ib_buffer_pool
-rw-r----- 1 systemd-coredump input 12582912 3月 20 19:28 ibdata1
-rw-r----- 1 systemd-coredump input 12582912 3月 20 19:28 ibtmp1
drwxr-x--- 2 systemd-coredump input 4096 3月 20 19:28 '#innodb_redo'
drwxr-x--- 2 systemd-coredump input 187 3月 20 19:28 '#innodb_temp'
drwxr-x--- 2 systemd-coredump input 143 3月 20 19:28 mysql
-rw-r----- 1 systemd-coredump input 31457280 3月 20 19:28 mysql.ibd
drwxr-x--- 2 systemd-coredump input 8192 3月 20 19:28 performance_schema
-rw------- 1 systemd-coredump input 1676 3月 20 19:28 private_key.pem
创建数据库并验证持久化
bash
[root@docker02.oldboylinux.cn /app/mysql/data]# docker exec -it db mysql -uroot -p1 -e 'create database lidao;'
mysql: [Warning] Using a password on the command line interface can be insecure.
# 目录多了个lidao
[root@docker02.oldboylinux.cn /app/mysql/data]# ll
总用量 99636
-rw-r----- 1 systemd-coredump input 56 3月 20 19:28 auto.cnf
-rw-r----- 1 systemd-coredump input 2994206 3月 20 19:28 binlog.000001
-rw-r----- 1 systemd-coredump input 345 3月 20 19:32 binlog.000002
-rw-r----- 1 systemd-coredump input 32 3月 20 19:28 binlog.index
-rw------- 1 systemd-coredump input 1680 3月 20 19:28 ca-key.pem
-rw-r--r-- 1 systemd-coredump input 1112 3月 20 19:28 ca.pem
-rw-r--r-- 1 systemd-coredump input 1112 3月 20 19:28 client-cert.pem
-rw------- 1 systemd-coredump input 1676 3月 20 19:28 client-key.pem
-rw-r----- 1 systemd-coredump input 196608 3月 20 19:32 '#ib_16384_0.dblwr'
-rw-r----- 1 systemd-coredump input 8585216 3月 20 19:28 '#ib_16384_1.dblwr'
-rw-r----- 1 systemd-coredump input 5657 3月 20 19:28 ib_buffer_pool
-rw-r----- 1 systemd-coredump input 12582912 3月 20 19:32 ibdata1
-rw-r----- 1 systemd-coredump input 12582912 3月 20 19:28 ibtmp1
drwxr-x--- 2 systemd-coredump input 4096 3月 20 19:28 '#innodb_redo'
drwxr-x--- 2 systemd-coredump input 187 3月 20 19:28 '#innodb_temp'
drwxr-x--- 2 systemd-coredump input 6 3月 20 19:32 lidao
删除容器并验证数据持久化
bash
[root@docker02.oldboylinux.cn /app/mysql/data]# docker rm -f db
db
[root@docker02.oldboylinux.cn /app/mysql/data]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 删除后查看目录依然存在
[root@docker02.oldboylinux.cn /app/mysql/data]# ll
总用量 99636
-rw-r----- 1 systemd-coredump input 56 3月 20 19:28 auto.cnf
-rw-r----- 1 systemd-coredump input 2994206 3月 20 19:28 binlog.000001
-rw-r----- 1 systemd-coredump input 345 3月 20 19:32 binlog.000002
-rw-r----- 1 systemd-coredump input 32 3月 20 19:28 binlog.index
-rw------- 1 systemd-coredump input 1680 3月 20 19:28 ca-key.pem
-rw-r--r-- 1 systemd-coredump input 1112 3月 20 19:28 ca.pem
-rw-r--r-- 1 systemd-coredump input 1112 3月 20 19:28 client-cert.pem
-rw------- 1 systemd-coredump input 1676 3月 20 19:28 client-key.pem
-rw-r----- 1 systemd-coredump input 196608 3月 20 19:32 '#ib_16384_0.dblwr'
-rw-r----- 1 systemd-coredump input 8585216 3月 20 19:28 '#ib_16384_1.dblwr'
-rw-r----- 1 systemd-coredump input 5657 3月 20 19:28 ib_buffer_pool
-rw-r----- 1 systemd-coredump input 12582912 3月 20 19:32 ibdata1
-rw-r----- 1 systemd-coredump input 12582912 3月 20 19:28 ibtmp1
drwxr-x--- 2 systemd-coredump input 4096 3月 20 19:28 '#innodb_redo'
drwxr-x--- 2 systemd-coredump input 187 3月 20 19:28 '#innodb_temp'
drwxr-x--- 2 systemd-coredump input 6 3月 20 19:32 lidao
drwxr-x--- 2 systemd-coredump input 143 3月 20 19:28 mysql
-rw-r----- 1 systemd-coredump input 31457280 3月 20 19:32 mysql.ibd
drwxr-x--- 2 systemd-coredump input 8192 3月 20 19:28 performance_schema
-rw------- 1 systemd-coredump input 1676 3月 20 19:28 private_key.pem
-rw-r--r-- 1 systemd-coredump input 452 3月 20 19:28 public_key.pem
-rw-r--r-- 1 systemd-coredump input 1112 3月 20 19:28 server-cert.pem
-rw------- 1 systemd-coredump input 1676 3月 20 19:28 server-key.pem
drwxr-x--- 2 systemd-coredump input 28 3月 20 19:28 sys
-rw-r----- 1 systemd-coredump input 16777216 3月 20 19:30 undo_001
-rw-r----- 1 systemd-coredump input 16777216 3月 20 19:32 undo_002
重新运行容器并验证数据库
bash
[root@docker02.oldboylinux.cn /app/mysql/data]# docker exec -it db mysql -uroot -p1 -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| lidao | <---- <--- <--
| mysql |
| performance_schema |
| sys |
+--------------------+
启动 Nginx 容器并映射配置文件和站点目录
bash
[root@docker02.oldboylinux.cn /app/mysql/data]# mkdir -p /app/code/bird/
[root@docker02.oldboylinux.cn /app/mysql/data]# cd /app/code/bird/
[root@docker02.oldboylinux.cn /app/code/bird]# mv ~/default.conf .
[root@docker02.oldboylinux.cn /app/code/bird]# vim default.conf
[root@docker02.oldboylinux.cn /app/code/bird]# mv ~/bird.tar.gz .
[root@docker02.oldboylinux.cn /app/code/bird]# mkdir code/
[root@docker02.oldboylinux.cn /app/code/bird]# ll
总用量 96
-rw-r--r-- 1 root root 91622 2月 27 11:37 bird.tar.gz
drwxr-xr-x 2 root root 6 3月 20 20:01 code
-rw-r--r-- 1 root root 361 3月 20 19:48 default.conf
# 查看是否占用端口
[root@docker02.oldboylinux.cn /app/code/bird]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2e05998add7f mysql:8.0-debian "docker-entrypoint.s…" 27 minutes ago Up 27 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp db
# 运行容器并映射配置文件和站点目录
[root@docker02.oldboylinux.cn /app/code/bird]# docker run -d -p 80:80 --name ngx_volume --restart always -v /app/code/bird/default.conf:/etc/nginx/conf.d/default.conf -v /app/code/bird/code/:/usr/share/nginx/html nginx:1.24
7c4c3d42a788878799ff34b0a7258c2c0eb0c134f8818a441b2fb48f3aced334
# 检查 ngx_volume 是否运行
[root@docker02.oldboylinux.cn /app/code/bird]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7c4c3d42a788 nginx:1.24 "/docker-entrypoint.…" 4 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp ngx_volume
2e05998add7f mysql:8.0-debian "docker-entrypoint.s…" 42 minutes ago Up 42 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp db
创建自定义镜像 Dockerfile
书写 Dockerfile
bash
[root@docker02.oldboylinux.cn /test]# cat Dockerfile
-----------------------------------------------------------------
# 使用官方 Nginx 1.24 镜像作为基础镜像
FROM nginx:1.24
# 添加镜像元数据
LABEL author=1234 url=www.linuxpath.cn desc="FlyBird"
# VARS
ENV CODE bird.tar.gz
ENV CODE_DIR /usr/share/nginx/html/
ENV MSG 测试bird
ADD default.conf /etc/nginx/conf.d/default.conf
# 用变量试试
# ADD bird.tar.gz /usr/share/nginx/html
ADD ${CODE} ${CODE_DIR}
RUN echo {$MSG}>${CODE_DIR}lidao.html
# 代码目录测试
WORKDIR ${CODE_DIR}
RUN touch worktest.txt
# 数据卷
VOLUME ${CODE_DIR}
# 告诉 Docker 容器将会监听 80 端口和 443 端口,仅作声明作用
# 这两个端口是 Web 服务的默认 HTTP 和 HTTPS 端口
EXPOSE 80 443
# 启动 Nginx 服务,并通过 -g "daemon off;" 让 Nginx 在前台运行
# 这样容器不会退出,并且可以持续提供服务
CMD ["nginx", "-g", "daemon off;"]
------------------------------------------------------------------
创建镜像
bash
[root@docker02.oldboylinux.cn /test]# docker build -t test02:02 .
查看镜像
bash
[root@docker02.oldboylinux.cn /test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test02 02 c1197d2e93d1 8 minutes ago 142MB
运行并查看环境变量是否设置成功
bash
[root@docker02.oldboylinux.cn /test]# docker build -t test02:02 .
# 查看 test02 镜像的环境变量
[root@docker02.oldboylinux.cn /test]# docker inspect test02:02
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.24.0",
"NJS_VERSION=0.7.12",
"PKG_RELEASE=1~bullseye",
"CODE=bird.tar.gz",
"CODE_DIR=/usr/share/nginx/html/",
"MSG=测试bird"
],
"Cmd": [
"nginx",
"-g",
"daemon off"
]
Dockerfile 指令详解
ENV - 设置环境变量
ENV
用于在容器中设置环境变量,这些变量在容器运行时可用。
bash
# 示例
ENV MYSQL_ROOT_PASSWORD=1
在容器中查看环境变量:
bash
[root@docker02.oldboylinux.cn ~]# docker exec -it db /bin/bash
root@2e05998add7f:/# env
MYSQL_MAJOR=8.0
HOSTNAME=2e05998add7f
PWD=/
MYSQL_ROOT_PASSWORD=1
HOME=/root
MYSQL_VERSION=8.0.33-1debian11
GOSU_VERSION=1.16
TERM=xterm
SHLVL=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_=/usr/bin/env
WORKDIR - 设置工作目录
WORKDIR
用于设置容器的工作目录,类似于 cd
命令。
bash
# 示例
WORKDIR /app/code/exam/
在容器中验证工作目录:
bash
[root@docker02.oldboylinux.cn ~]# docker exec -it 3c4e84edb854 /bin/bash
root@3c4e84edb854:/app/code/exam# pwd
/app/code/exam
数据卷
VOLUME
用于定义数据卷,使得容器中的目录可以持久化存储。
bash
# 示例
VOLUME /var/lib/mysql
查看数据卷:
bash
[root@docker02.oldboylinux.cn ~]# docker inspect db
"Volumes": {
"/var/lib/mysql": {}
},
ADD vs COPY 的区别
特性 | ADD | COPY |
---|---|---|
功能 | 支持从本地或远程 URL 复制文件,并自动解压压缩包(如 .tar.gz ) | 仅支持从本地文件系统复制文件 |
解压能力 | ✅ 自动解压压缩文件 | ❌ 无解压功能 |
远程文件支持 | ✅ 可从网络 URL 下载文件(如 ADD http://example.com/file.txt /app/ ) | ❌ 仅支持本地文件 |
官方推荐 | 慎用(优先用 COPY,除非需要解压或远程文件) | 优先使用(简单透明,不易出错) |
典型场景 | 需要解压配置文件或下载依赖项时 | 单纯复制本地文件到容器 |
示例:
bash
# ADD 示例:解压本地压缩包并复制到容器
ADD config.tar.gz /app/config/ # 自动解压到/app/config/
# COPY 示例:直接复制本地文件
COPY requirements.txt /app/
CMD vs ENTRYPOINT 的区别
特性 | CMD | ENTRYPOINT |
---|---|---|
命令覆盖性 | ✅ 可被 docker run 覆盖(如 docker run image ls -l 会替换 CMD) | ❌ 不可被覆盖,docker run 参数会作为 ENTRYPOINT 的子命令追加参数 |
默认执行 | 定义容器启动时的默认命令 | 定义容器必须执行的根命令(类似“入口函数”) |
参数传递 | 运行时的额外参数会替换 CMD 命令 | 运行时的额外参数会作为 ENTRYPOINT 的参数(如 docker run image arg1 arg2 ) |
典型场景 | 定义可替换的默认启动命令(如 CMD ["nginx"] ) | 定义固定命令模板(如 ENTRYPOINT ["dockerize"] + CMD ["-template"] ) |
示例:
bash
# CMD 示例:默认启动 Nginx(可被覆盖)
CMD ["nginx", "-g", "daemon off;"]
# ENTRYPOINT 示例:强制使用 curl 命令(参数通过 docker run 传递)
ENTRYPOINT ["curl"]
CMD ["-s", "http://example.com"] # 运行时可追加参数:`docker run image -I`
ARG vs ENV 的区别
对比项 | ARG | ENV |
---|---|---|
定义位置 | Dockerfile 中通过 ARG 指令定义 | Dockerfile 中通过 ENV 指令定义 |
作用阶段 | 仅构建阶段(Build Time) | 构建阶段 + 运行阶段(Build & Runtime) |
持久性 | 构建完成后自动清除 | 持久化到容器环境 |
业务如何容器化
业务容器化示例:基于 Tomcat 部署 WAR 包
容器化的核心是选择合适的基础镜像、优化配置、合理构建 Docker 镜像,然后推送到私有仓库以便团队协作和自动化部署。
1. 选择基础镜像
选择合适的 Linux 发行版作为基础镜像,这里使用 Tomcat 官方镜像:
bash
FROM tomcat:9.0
tomcat:9.0
是官方提供的 Tomcat 9 版本,已包含 JDK 和 Tomcat 环境。
2. 部署 JDK
如果基础镜像没有 JDK,需要手动安装:
bash
FROM ubuntu:20.04
RUN apt update && apt install -y openjdk-11-jdk
说明:
- 适用于从零搭建 Tomcat 环境的情况。
3. 部署 Tomcat
如果使用自定义镜像,需要手动安装 Tomcat:
bash
RUN apt install -y wget && \
wget https://downloads.apache.org/tomcat/tomcat-9/v9.0.65/bin/apache-tomcat-9.0.65.tar.gz && \
tar -xzf apache-tomcat-9.0.65.tar.gz -C /opt && \
mv /opt/apache-tomcat-9.0.65 /opt/tomcat
说明:
- 适用于无法使用官方镜像,需要手动配置 Tomcat 的情况。
4. 上传 WAR 包
将 myapp.war
复制到 Tomcat webapps
目录:
bash
COPY myapp.war /usr/local/tomcat/webapps/
说明:
COPY
指令会将本地的myapp.war
复制到容器的webapps
目录,Tomcat 启动时会自动部署。
5. 优化 Tomcat 配置
Tomcat 默认配置可能无法满足高并发需求,因此需要调整:
bash
RUN echo "JAVA_OPTS='-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom'" >> /usr/local/tomcat/bin/setenv.sh
说明:
-Xms512m -Xmx1024m
限制 JVM 最小 512MB,最大 1024MB。-Djava.security.egd=file:/dev/./urandom
解决 Tomcat 启动慢的问题。
6. 开放端口
bash
EXPOSE 8080
说明:
- 让容器监听 8080 端口,外部可访问 Web 服务。
7. 启动 Tomcat
bash
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]
说明:
- 使用
CMD
指令在容器启动时运行 Tomcat。
8. 构建并运行 Docker 容器
执行以下命令:
bash
docker build -t myapp:v1 .
docker run -d -p 8080:8080 --name myapp-container myapp:v1
说明:
docker build
生成镜像myapp:v1
。docker run
以守护进程模式(-d
)运行容器,映射 8080 端口。
9. 推送到私有仓库
如果有私有 Docker 仓库(如 Harbor、阿里云镜像仓库):
bash
docker tag myapp:v1 myregistry.com/myapp:v1
docker push myregistry.com/myapp:v1
说明:
docker tag
给镜像打上私有仓库标签。docker push
上传镜像,方便团队协作。