Docker 完整教程
本教程侧重于命令实践和理解,提供可在本地环境测试的实例,每章结束都有总结要点。
目录
Docker 基础概念和安装
Docker 常用命令实践
Docker 网络机制详解
Docker 数据卷和挂载
Dockerfile 编写和镜像构建
Docker Compose 多容器编排
Docker 镜像管理和仓库操作
本篇内容较多,建议在侧边栏根据需要点击目录进行跳转。
第1章:Docker 基础概念和安装
1.1 什么是 Docker
Docker 是一个开源的容器化平台,它允许开发者将应用程序及其依赖项打包到一个轻量级、可移植的容器中。
核心概念
镜像 (Image) :只读的模板,包含运行应用所需的代码、运行时、库、环境变量和配置文件
容器 (Container) :镜像的运行实例,是一个独立的进程
仓库 (Repository) :存储镜像的地方,如 Docker Hub
Docker vs 虚拟机
特性
Docker 容器
虚拟机
启动速度
秒级
分钟级
资源占用
低
高
隔离级别
进程级
操作系统级
移植性
高
中等
1.2 Docker 安装
方法1:进入官网 ,下载 Docker Desktop。
macOS 可以使用 Homebrew 安装:
1 brew install --cask docker
Linux (Ubuntu) 安装
1 2 3 4 5 6 sudo apt-get update sudo apt install docker.io -y sudo usermod -aG docker $USER
1.3 验证安装
1 2 3 4 5 6 7 8 docker --version docker info
1.4 Docker 架构
Docker 使用客户端-服务器架构:
1 2 3 4 5 ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Docker │ │ Docker │ │ Docker │ │ Client │───▶│ Daemon │───▶│ Registry │ │ │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘
Docker Client :用户与 Docker 交互的主要方式
Docker Daemon :监听 Docker API 请求并管理 Docker 对象
Docker Registry :存储 Docker 镜像的服务
1.5 实践练习
练习1:检查 Docker 状态
1 2 3 4 5 6 7 8 9 10 11 docker version docker ps docker ps -a docker images
练习2:运行第一个容器
1 2 3 4 5 6 7 8 9 docker run -it ubuntu:20.04 /bin/bash echo "Hello from inside Docker container!" cat /etc/os-releaseexit
练习3:后台运行容器
1 2 3 4 5 6 7 8 9 10 11 12 13 docker run -d --name my-nginx -p 8080:80 nginx docker ps docker stop my-nginx docker rm my-nginx
1.6 常见问题排查
权限问题:
1 2 3 4 5 groups $USER newgrp docker
服务未启动:
1 2 3 4 5 sudo systemctl start docker sudo systemctl status docker
本章总结
在本章中,我们学习了:
Docker 基本概念 :了解了镜像、容器、仓库的概念和 Docker 与虚拟机的区别
安装 Docker :在不同操作系统上安装 Docker 的方法
验证安装 :通过运行 hello-world 容器验证 Docker 正常工作
Docker 架构 :理解客户端-服务器架构模式
基础实践 :运行第一个容器,体验 Docker 的基本操作
关键要点 :
Docker 容器比虚拟机更轻量、启动更快
容器是镜像的运行实例
通过 docker run
命令可以快速启动容器
容器具有良好的隔离性和可移植性
下一章我们将深入学习 Docker 的常用命令,掌握容器的生命周期管理。
第2章:Docker 常用命令实践
2.1 镜像管理命令
拉取镜像
1 2 3 4 5 6 7 8 docker pull nginx docker pull nginx:1.21 docker pull registry.cn-hangzhou.aliyuncs.com/library/nginx
查看镜像
1 2 3 4 5 6 7 8 9 10 11 docker images docker inspect nginx docker history nginx docker search python
删除镜像
1 2 3 4 5 6 7 8 9 10 11 docker rmi nginx:latest docker rmi nginx redis mysql docker rmi -f nginx docker image prune
2.2 容器生命周期管理
创建和启动容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 docker run nginx docker run -d nginx docker run -d --name my-nginx nginx docker run -d -p 8080:80 --name web-server nginx docker run -d -e MYSQL_ROOT_PASSWORD=123456 mysql docker run -it ubuntu:20.04 /bin/bash
查看容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker ps docker ps -a docker inspect container_name docker stats docker top container_name
停止和删除容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 docker stop container_name docker kill container_name docker restart container_name docker rm container_name docker rm -f container_name docker container prune
2.3 容器交互命令
进入容器
1 2 3 4 5 6 7 8 docker exec -it container_name /bin/bash docker exec container_name ls -la docker exec -it --user root container_name /bin/bash
文件操作
1 2 3 4 5 6 7 8 docker cp container_name:/path/to/file /host/path/ docker cp /host/path/file container_name:/path/to/ docker diff container_name
日志查看
1 2 3 4 5 6 7 8 9 10 11 docker logs container_name docker logs -f container_name docker logs --tail 100 container_name docker logs --since "2023-01-01" container_name
2.4 实践练习
练习1:部署 Web 服务器
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 mkdir -p /tmp/docker-tutorialcd /tmp/docker-tutorialcat > index.html << 'EOF' <!DOCTYPE html> <html> <head > <title>My Docker Web Server</title> </head> <body> <h1>Hello from Docker!</h1> <p>This is served by nginx running in a Docker container.</p> </body> </html> EOF docker run -d \ --name my-web-server \ -p 8080:80 \ -v $(pwd ):/usr/share/nginx/html \ nginx curl http://localhost:8080 docker ps docker logs my-web-server docker stop my-web-server docker rm my-web-server
练习2:数据库容器
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 docker run -d \ --name mysql-db \ -e MYSQL_ROOT_PASSWORD=mypassword \ -e MYSQL_DATABASE=testdb \ -p 3306:3306 \ mysql:8.0 sleep 30docker exec -it mysql-db mysql -uroot -pmypassword docker stop mysql-db docker rm mysql-db
练习3:Python 应用容器
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 42 43 44 45 46 47 48 49 mkdir python-appcd python-appcat > app.py << 'EOF' from flask import Flask import os app = Flask(__name__) @app.route('/' ) def hello(): return f"Hello from Python app running in Docker!<br>Container ID: {os.uname().nodename}" @app.route('/health' ) def health(): return "OK" if __name__ == '__main__' : app.run(host='0.0.0.0' , port=5000) EOF echo "Flask==2.3.3" > requirements.txtdocker run -d \ --name python-app \ -p 5000:5000 \ -v $(pwd ):/app \ -w /app \ python:3.11-slim \ bash -c "pip install -r requirements.txt && python app.py" sleep 10curl http://localhost:5000 curl http://localhost:5000/health docker logs python-app docker stop python-app docker rm python-app cd ..
2.5 高级命令技巧
批量操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker stop $(docker ps -q) docker rm $(docker ps -aq) docker rmi $(docker images -q) docker system prune docker system prune -a --volumes
资源限制
1 2 3 4 5 6 7 8 9 10 11 docker run -d --memory="512m" nginx docker run -d --cpus="1.5" nginx docker run -d --memory="1g" --cpus="2" nginx docker stats
网络配置
1 2 3 4 5 6 7 8 9 10 11 12 docker run -d --network host nginx docker network create my-network docker run -d --network my-network --name app1 nginx docker run -d --network my-network --name app2 nginx docker exec app1 ping app2
关于网络机制,这里有很多细节需要展开,我们在 第3章 中详细讲解。
2.6 常见问题和解决方案
端口冲突
1 2 3 4 5 sudo netstat -tulpn | grep :8080 docker run -d -p 8081:80 nginx
容器无法启动
1 2 3 4 5 6 7 8 docker logs container_name docker inspect container_name docker run -it image_name /bin/bash
镜像拉取失败
1 2 3 4 5 6 7 8 9 docker pull registry.cn-hangzhou.aliyuncs.com/library/nginx { "registry-mirrors" : [ "https://registry.cn-hangzhou.aliyuncs.com" ] }
本章总结
在本章中,我们深入学习了 Docker 的常用命令:
镜像管理 :掌握了镜像的拉取、查看、删除等操作
容器生命周期 :学会了容器的创建、启动、停止、删除
容器交互 :了解了如何进入容器、查看日志、复制文件
实践应用 :通过 Web 服务器、数据库、Python 应用的部署加深理解
高级技巧 :掌握了批量操作、资源限制、网络配置等高级用法
关键命令总结 :
docker run
:创建并运行容器
docker ps
:查看容器状态
docker exec
:在容器中执行命令
docker logs
:查看容器日志
docker stop/start/restart
:控制容器状态
最佳实践 :
为容器指定有意义的名称
合理使用端口映射和数据卷
定期清理未使用的容器和镜像
使用资源限制防止容器占用过多资源
下一章我们将学习 Docker 网络机制,了解容器间如何通信。
第3章:Docker 网络机制详解
3.1 Docker 网络基础
Docker 网络是容器间通信和容器与外部世界通信的基础。理解网络机制对于构建复杂的容器化应用至关重要。
每个 Docker 容器都有自己的网络命名空间,包括:独立的网络接口,路由表,iptables 规则和端口空间。
查看网络信息
1 2 3 4 5 6 7 8 docker network ls docker network inspect bridge docker inspect container_name | grep -A 20 "NetworkSettings"
3.2 Docker 网络驱动类型
运行 docker network ls
查看网络,比如
1 2 3 4 5 6 7 ❯ docker network ls NETWORK ID NAME DRIVER SCOPE fef63891b2a7 bridge bridge local 150f1dc61078 nginx_default bridge local ce0e3369b5e1 host host local 050afab805f4 none null local
可以看到存在三种类型:bridge, host, none。
1. Bridge 网络(默认)
Bridge 是 Docker 的默认网络驱动,适用于单主机上的容器通信。
作用:为容器提供独立的网络命名空间,同时允许容器间通信
特点:容器获得私有 IP(通常是 172.17.x.x),通过 NAT 访问外网
使用场景:大部分单机容器应用的默认选择
常用命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 docker network inspect bridge docker run -d --name app1 nginx docker run -d --name app2 nginx docker inspect app1 | grep IPAddress docker inspect app2 | grep IPAddress docker exec app1 ping $(docker inspect app2 | grep IPAddress | head -1 | cut -d'"' -f4)
2. Host 网络
Host 网络模式下,容器直接使用主机的网络栈。
特点:容器直接使用主机的网络栈,没有网络隔离
性能:网络性能最好,没有 NAT 转换开销
风险:安全性较低,容器可以直接访问主机网络
1 2 3 4 5 6 7 8 docker run -d --network host --name host-app nginx docker exec host-app ip addr show curl http://localhost:80
3. None 网络
None 网络模式下,容器没有网络接口。
1 2 3 4 5 docker run -d --network none --name no-network alpine sleep 3600 docker exec no-network ip addr show
4. 自定义 Bridge 网络
自定义网络提供更好的隔离性和容器间的名称解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 docker network create --driver bridge my-network docker network inspect my-network docker run -d --network my-network --name web nginx docker run -d --network my-network --name db mysql:8.0 -e MYSQL_ROOT_PASSWORD=password docker exec web ping db docker exec db ping web
5. 自定义 Bridge 网络的 IP 段
Docker 默认使用 172.17.0.0/16 网段,如果服务器的 172.xx
网段被占用,为避免冲突,可以通过 /etc/docker/daemon.json
修改全局默认配置,举个例子:
1 2 3 4 5 6 7 8 { "bip" : "100.10.100.1/24" , "default-address-pools" : [ {"base" :"100.10.0.0/16" ,"size" :24} ] }
配置说明:
bip
:设置默认 bridge 网络的 IP 段
default-address-pools
:设置自定义网络的默认 IP 池
1 2 sudo systemctl restart docker
当然,也可以为单个容器创建指定 IP 段网络,比如
1 2 3 4 5 6 ```bash docker network create \ --subnet=10.10.0.0/24 \ --gateway=10.10.0.1 \ dev-network
3.3 端口映射
基本端口映射
通过 -p <host_port>:<container_port>
可以将容器端口映射到主机端口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker run -d -p 8080:80 nginx docker run -d -p 8080:80 -p 8443:443 nginx docker run -d -p 127.0.0.1:8080:80 nginx docker run -d -P nginx docker port container_name
高级端口配置
1 2 3 4 5 6 7 8 docker run -d -p 53:53/udp nginx docker run -d -p 8000-8010:8000-8010 nginx docker ps --format "table {{.Names}}\t{{.Ports}}"
3.4 实践练习
练习1:Web 应用 + 数据库通信
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 docker network create webapp-network docker run -d \ --name database \ --network webapp-network \ -e MYSQL_ROOT_PASSWORD=rootpass \ -e MYSQL_DATABASE=webapp \ mysql:8.0 sleep 30docker run -d \ --name webapp \ --network webapp-network \ -p 8080:80 \ nginx docker exec webapp ping database docker exec webapp apt-get update docker exec webapp apt-get install -y telnet docker exec webapp telnet database 3306 docker stop webapp database docker rm webapp database docker network rm webapp-network
练习2:负载均衡配置
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 42 43 44 45 46 47 48 49 50 docker network create lb-network docker run -d --name backend1 --network lb-network nginx docker run -d --name backend2 --network lb-network nginx docker run -d --name backend3 --network lb-network nginx mkdir -p /tmp/docker-tutorial/nginx-lbcat > /tmp/docker-tutorial/nginx-lb/nginx.conf << 'EOF' events { worker_connections 1024; } http { upstream backend { server backend1:80; server backend2:80; server backend3:80; } server { listen 80; location / { proxy_pass http://backend; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; } } } EOF docker run -d \ --name load-balancer \ --network lb-network \ -p 8080:80 \ -v /tmp/docker-tutorial/nginx-lb/nginx.conf:/etc/nginx/nginx.conf \ nginx for i in {1..6}; do curl -s http://localhost:8080 | grep -o "backend[0-9]" || echo "Request $i " done docker stop load-balancer backend1 backend2 backend3 docker rm load-balancer backend1 backend2 backend3 docker network rm lb-network
3.5 网络故障排查
常用网络调试命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 docker exec -it container_name bash apt-get update && apt-get install -y iputils-ping telnet curl netcat ping target_host telnet target_host port curl http://target_host:port nc -zv target_host port ip addr show ip route show netstat -tulpn ss -tulpn
常见网络问题
1 2 3 4 5 6 7 8 9 10 11 12 13 docker run --rm busybox ping google.com docker exec container1 ping container2 docker port container_name netstat -tulpn | grep port_number docker exec container_name nslookup google.com docker exec container_name cat /etc/resolv.conf
3.6 高级网络配置
网络别名
网络别名最大的用途是实现简单的负载均衡。多个容器可以使用同一个别名,Docker 会自动进行 DNS 轮询。
1 2 3 4 5 6 7 8 9 10 11 docker network create test-network docker run -d --name web1 --network web-cluster --network-alias webapp nginx docker run -d --name web2 --network web-cluster --network-alias webapp nginx docker run -d --name web3 --network web-cluster --network-alias webapp nginx docker run --rm --network web-cluster busybox nslookup webapp
多网络连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 docker network create frontend docker network create backend docker run -d --name db --network backend mysql:8.0 -e MYSQL_ROOT_PASSWORD=pass docker run -d --name app nginx docker network connect frontend app docker network connect backend app docker run -d --name web --network frontend nginx docker exec app ping db docker exec web ping app docker exec web ping db
网络策略和安全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 docker network create --internal secure-network docker run -d --name isolated --network secure-network nginx docker exec isolated ping google.com docker network create \ --driver bridge \ --subnet=192.168.100.0/24 \ --ip-range=192.168.100.128/25 \ --gateway=192.168.100.1 \ custom-subnet docker run -d --name fixed-ip --network custom-subnet --ip 192.168.100.130 nginx
本章总结
在本章中,我们全面学习了 Docker 网络机制:
网络基础 :理解了 Docker 网络的基本概念和命名空间隔离
网络驱动 :掌握了 Bridge、Host、None 和自定义网络的使用
端口映射 :学会了各种端口映射配置和高级用法
实践应用 :通过 Web 应用、微服务、负载均衡等场景加深理解
故障排查 :了解了网络问题的诊断和解决方法
高级配置 :掌握了网络别名、多网络连接、安全策略等高级特性
关键概念总结 :
网络隔离 :每个容器都有独立的网络命名空间
服务发现 :自定义网络中容器可以通过名称互相访问
端口映射 :将容器端口暴露到主机上
网络安全 :通过网络隔离实现安全边界
最佳实践要点 :
为不同的应用创建独立的自定义网络
避免使用默认 bridge 网络进行生产部署
合理规划端口映射,避免端口冲突
使用网络别名实现服务发现
实施网络隔离提高安全性
常见应用场景 :
前后端分离应用的网络隔离
负载均衡和服务发现
多环境部署的网络规划
容器集群的网络管理
下一章我们将学习 Docker 数据卷和挂载,了解如何持久化容器数据。
第4章:Docker 数据卷和挂载
4.1 数据持久化的重要性
容器是无状态的,当容器删除时,容器内的数据也会丢失。为了实现数据持久化,Docker 提供了多种数据存储方案。
数据丢失问题演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 docker run -it --name temp-container ubuntu:20.04 bash echo "Important data" > /tmp/important.txtcat /tmp/important.txtexit docker rm temp-container docker run -it --name temp-container ubuntu:20.04 bash cat /tmp/important.txt exit docker rm temp-container
4.2 Docker 存储类型
Docker 提供三种主要的数据存储方式:
1. Volumes(数据卷)
数据卷是 Docker 管理的存储区域,存储在主机文件系统中,但完全由 Docker 管理。
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 docker volume create my-volume docker volume ls docker volume inspect my-volume docker run -d --name web-server -v my-volume:/usr/share/nginx/html nginx docker run -it --rm -v my-volume:/data ubuntu:20.04 bash echo "<h1>Hello from Volume!</h1>" > /data/index.htmlexit curl http://localhost:80 docker stop web-server docker rm web-server docker volume rm my-volume
2. Bind Mounts(绑定挂载)
绑定挂载将主机文件系统的目录或文件直接挂载到容器中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mkdir -p /tmp/docker-tutorial/htmlecho "<h1>Hello from Bind Mount!</h1>" > /tmp/docker-tutorial/html/index.htmldocker run -d \ --name bind-web \ -p 8080:80 \ -v /tmp/docker-tutorial/html:/usr/share/nginx/html \ nginx curl http://localhost:8080 echo "<h1>Updated from Host!</h1>" > /tmp/docker-tutorial/html/index.htmlcurl http://localhost:8080 docker stop bind-web docker rm bind-web
3. tmpfs Mounts(临时文件系统挂载)
tmpfs 挂载将数据存储在主机内存中,容器停止时数据会丢失。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 docker run -d \ --name tmpfs-test \ --tmpfs /tmp:rw,noexec,nosuid,size=100m \ nginx docker exec tmpfs-test mount | grep tmpfs docker exec tmpfs-test bash -c "echo 'Temporary data' > /tmp/temp.txt" docker exec tmpfs-test cat /tmp/temp.txt docker restart tmpfs-test docker exec tmpfs-test cat /tmp/temp.txt docker stop tmpfs-test docker rm tmpfs-test
4.3 数据卷管理
数据卷操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 docker volume create app-data docker volume create db-data docker volume create logs docker volume ls docker volume inspect app-data docker volume rm logs docker volume prune docker system df
数据卷备份和恢复
这里 --rm
表示创建后删除停止的容器,常用语一次性任务。
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 docker volume create backup-demo docker run --rm -v backup-demo:/data ubuntu:20.04 bash -c " echo 'Important data 1' > /data/file1.txt echo 'Important data 2' > /data/file2.txt mkdir /data/subdir echo 'Subdirectory data' > /data/subdir/file3.txt " docker run --rm \ -v backup-demo:/source \ -v $(pwd ):/backup \ ubuntu:20.04 \ tar czf /backup/backup-demo.tar.gz -C /source . ls -la backup-demo.tar.gzdocker volume create restore-demo docker run --rm \ -v restore-demo:/target \ -v $(pwd ):/backup \ ubuntu:20.04 \ tar xzf /backup/backup-demo.tar.gz -C /target docker run --rm -v restore-demo:/data ubuntu:20.04 find /data -type f -exec cat {} \; docker volume rm backup-demo restore-demo rm backup-demo.tar.gz
4.4 实践练习
练习1:数据库数据持久化
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 42 43 44 45 46 47 48 docker volume create mysql-data docker run -d \ --name mysql-persistent \ -e MYSQL_ROOT_PASSWORD=mypassword \ -e MYSQL_DATABASE=testdb \ -v mysql-data:/var/lib/mysql \ -p 3306:3306 \ mysql:8.0 sleep 30docker exec -it mysql-persistent mysql -uroot -pmypassword -e " USE testdb; CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50)); INSERT INTO users (name) VALUES ('Alice'), ('Bob'), ('Charlie'); SELECT * FROM users; " docker stop mysql-persistent docker rm mysql-persistent docker run -d \ --name mysql-restored \ -e MYSQL_ROOT_PASSWORD=mypassword \ -v mysql-data:/var/lib/mysql \ -p 3306:3306 \ mysql:8.0 sleep 30docker exec -it mysql-restored mysql -uroot -pmypassword -e " USE testdb; SELECT * FROM users; " docker stop mysql-restored docker rm mysql-restored docker volume rm mysql-data
练习2:多容器数据共享
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 docker volume create shared-data docker run -d \ --name producer \ -v shared-data:/data \ ubuntu:20.04 \ bash -c " while true; do echo \"\$(date): Producer data\" >> /data/producer.log sleep 5 done " docker run -d \ --name consumer \ -v shared-data:/data \ ubuntu:20.04 \ bash -c " while true; do if [ -f /data/producer.log ]; then echo \"Consumer read: \$(tail -1 /data/producer.log)\" fi sleep 3 done " docker run -d \ --name processor \ -v shared-data:/data \ ubuntu:20.04 \ bash -c " while true; do if [ -f /data/producer.log ]; then wc -l /data/producer.log > /data/stats.txt echo \"Processed at \$(date)\" >> /data/stats.txt fi sleep 10 done " echo "Producer logs:" docker logs producer --tail 5 echo "Consumer logs:" docker logs consumer --tail 5 echo "Processor logs:" docker logs processor --tail 5 docker run --rm -v shared-data:/data ubuntu:20.04 ls -la /data docker run --rm -v shared-data:/data ubuntu:20.04 cat /data/stats.txt docker stop producer consumer processor docker rm producer consumer processor docker volume rm shared-data
4.5 高级挂载选项
只读挂载
1 2 3 4 5 6 7 8 9 10 11 12 mkdir -p /tmp/docker-tutorial/readonly-dataecho "Read-only data" > /tmp/docker-tutorial/readonly-data/config.txtdocker run -it --rm \ -v /tmp/docker-tutorial/readonly-data:/data:ro \ ubuntu:20.04 bash
挂载单个文件
1 2 3 4 5 6 7 8 9 10 11 echo "database_host=localhost" > /tmp/docker-tutorial/app.confdocker run -it --rm \ -v /tmp/docker-tutorial/app.conf:/app/config/app.conf:ro \ ubuntu:20.04 bash
挂载选项
1 2 3 4 5 6 7 8 9 10 11 12 docker run -d \ --name mount-options-test \ --mount type =bind ,source =/tmp/docker-tutorial,target=/data,readonly \ nginx docker inspect mount-options-test | grep -A 10 "Mounts" docker stop mount-options-test docker rm mount-options-test
4.6 性能和最佳实践
性能考虑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 docker volume create perf-volume docker run --rm \ -v perf-volume:/data \ ubuntu:20.04 \ bash -c "time dd if=/dev/zero of=/data/test bs=1M count=100" mkdir -p /tmp/docker-tutorial/perf-binddocker run --rm \ -v /tmp/docker-tutorial/perf-bind:/data \ ubuntu:20.04 \ bash -c "time dd if=/dev/zero of=/data/test bs=1M count=100" docker run --rm \ --tmpfs /data:rw,size=200m \ ubuntu:20.04 \ bash -c "time dd if=/dev/zero of=/data/test bs=1M count=100" docker volume rm perf-volume rm -rf /tmp/docker-tutorial/perf-bind
三种方式比较:
存储类型
性能特点
适用场景
tmpfs
最快
临时文件、缓存、高频读写的临时数据
数据卷 (Volume)
较快
生产环境的首选
绑定挂载 (Bind Mount)
最慢
开发调试、直接访问宿主机文件
最佳实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 docker volume create app-logs docker run -d -v app-logs:/var/log/app nginx docker volume create app-data docker volume create app-config docker volume create app-logs docker run --rm \ -v app-data:/source:ro \ -v $(pwd ):/backup \ ubuntu:20.04 \ tar czf /backup/app-data-$(date +%Y%m%d).tar.gz -C /source . docker system df -v docker volume rm app-logs app-data app-config
本章总结
在本章中,我们深入学习了 Docker 数据卷和挂载机制:
数据持久化重要性 :理解了容器数据丢失问题和持久化的必要性
存储类型 :掌握了 Volumes、Bind Mounts、tmpfs Mounts 三种存储方式
数据卷管理 :学会了数据卷的创建、查看、备份、恢复等操作
实践应用 :通过数据库持久化、开发环境同步、多容器数据共享等场景加深理解
高级选项 :了解了只读挂载、单文件挂载、挂载选项等高级用法
性能优化 :掌握了不同存储类型的性能特点和最佳实践
关键概念总结 :
数据卷 :Docker 管理的持久化存储,推荐用于生产环境
绑定挂载 :直接挂载主机目录,适合开发环境
tmpfs 挂载 :内存存储,适合临时数据
数据共享 :多个容器可以共享同一个数据卷
存储选择指南 :
生产数据 :使用 Volumes
开发调试 :使用 Bind Mounts
临时缓存 :使用 tmpfs Mounts
配置文件 :使用只读 Bind Mounts
日志文件 :使用 Volumes 或 Bind Mounts
下一章我们将学习 Dockerfile 编写和镜像构建,了解如何创建自定义镜像。
第5章:Dockerfile 编写和镜像构建
5.1 Dockerfile 基础
Dockerfile 是一个文本文件,包含了构建 Docker 镜像的所有指令。通过 Dockerfile,我们可以自动化地创建自定义镜像。
Dockerfile 基本结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 FROM ubuntu:20.04 LABEL maintainer="your-email@example.com" WORKDIR /app COPY . . RUN apt-get update && apt-get install -y python3 EXPOSE 8080 CMD ["python3" , "app.py" ]
第一个 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 28 29 30 mkdir -p /tmp/docker-tutorial/first-dockerfilecd /tmp/docker-tutorial/first-dockerfilecat > app.py << 'EOF' print ("Hello from my first Docker image!" )print ("This is a simple Python application." )EOF cat > Dockerfile << 'EOF' FROM python:3.11-slim WORKDIR /app COPY app.py . CMD ["python" , "app.py" ] EOF docker build -t my-first-image . docker run --rm my-first-image docker images my-first-image
5.2 Dockerfile 指令详解
FROM - 基础镜像
1 2 3 4 5 6 7 8 9 FROM python:3.11 -slimFROM node:18.17 .0 -alpineFROM golang:1.21 AS builderFROM alpine:latest AS runtime
RUN - 执行命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 RUN apt-get update RUN apt-get update && \ apt-get install -y \ curl \ vim \ git && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* RUN echo "Hello World" RUN ["echo" , "Hello World" ]
COPY 和 ADD
1 2 3 4 5 6 7 8 9 10 11 COPY app.py /app/ COPY requirements.txt /app/ COPY . /app/ ADD https://example.com/file.tar.gz /tmp/ ADD archive.tar.gz /app/ COPY --chown =1000:1000 app.py /app/
WORKDIR - 工作目录
1 2 3 4 5 6 7 8 WORKDIR /app WORKDIR subdir WORKDIR /var/log
ENV - 环境变量
1 2 3 4 5 6 7 8 9 ENV NODE_ENV=productionENV PORT=3000 ENV DATABASE_URL=postgresql://localhost/mydbENV NODE_ENV=production \ PORT=3000 \ DEBUG=false
EXPOSE - 暴露端口
1 2 3 4 5 6 7 8 9 EXPOSE 8080 EXPOSE 8080 8443 EXPOSE 53 /udpEXPOSE 80 /tcp
CMD 和 ENTRYPOINT
1 2 3 4 5 6 7 8 9 10 CMD ["python" , "app.py" ] CMD python app.py ENTRYPOINT ["python" , "app.py" ] ENTRYPOINT ["python" ] CMD ["app.py" ]
为方便解释区别,以组合为例,比如:
1 2 3 FROM python:3.9 ENTRYPOINT ["python" ] CMD ["app.py" ]
运行效果:
1 2 3 4 5 6 7 8 9 10 11 docker run myapp docker run myapp test.py docker run myapp app.py --debug
5.3 实践练习
练习1:Python Web 应用
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 mkdir -p /tmp/docker-tutorial/python-webappcd /tmp/docker-tutorial/python-webappcat > app.py << 'EOF' from flask import Flask, jsonify import os import socket app = Flask(__name__) @app.route('/' ) def hello(): return jsonify({ 'message' : 'Hello from Python Web App!' , 'hostname' : socket.gethostname(), 'environment' : os.environ.get('ENVIRONMENT' , 'development' ) }) @app.route('/health' ) def health(): return jsonify({'status' : 'healthy' }) if __name__ == '__main__' : app.run(host='0.0.0.0' , port=int(os.environ.get('PORT' , 5000))) EOF cat > requirements.txt << 'EOF' Flask==2.3.3 gunicorn==21.2.0 EOF cat > Dockerfile << 'EOF' FROM python:3.11-slim ENV PYTHONUNBUFFERED=1 ENV PORT=5000 ENV ENVIRONMENT=production RUN groupadd -r appuser && useradd -r -g appuser appuser WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app.py . RUN chown -R appuser:appuser /app USER appuser EXPOSE 5000 HEALTHCHECK --interval=30s --timeout =3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:5000/health || exit 1 CMD ["gunicorn" , "--bind" , "0.0.0.0:5000" , "app:app" ] EOF docker build -t python-webapp . docker run -d --name webapp -p 5000:5000 python-webapp sleep 5curl http://localhost:5000 curl http://localhost:5000/health docker ps docker stop webapp docker rm webapp
练习2:Node.js 应用(多阶段构建)
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 mkdir -p /tmp/docker-tutorial/nodejs-appcd /tmp/docker-tutorial/nodejs-appcat > package.json << 'EOF' { "name" : "nodejs-docker-app" , "version" : "1.0.0" , "description" : "Node.js app with Docker" , "main" : "server.js" , "scripts" : { "start" : "node server.js" , "dev" : "nodemon server.js" }, "dependencies" : { "express" : "^4.18.2" }, "devDependencies" : { "nodemon" : "^3.0.1" } } EOF cat > server.js << 'EOF' const express = require('express' ); const app = express(); const port = process.env.PORT || 3000; app.get('/' , (req, res) => { res.json({ message: 'Hello from Node.js Docker app!' , timestamp: new Date().toISOString(), environment: process.env.NODE_ENV || 'development' }); }); app.get('/health' , (req, res) => { res.json({ status: 'healthy' }); }); app.listen(port, '0.0.0.0' , () => { console.log(`Server running on port ${port} `); }); EOF cat > .dockerignore << 'EOF' node_modules npm-debug.log .git .gitignore README.md .env .nyc_output coverage .DS_Store EOF cat > Dockerfile << 'EOF' FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production && npm cache clean --force FROM node:18-alpine AS runtime RUN addgroup -g 1001 -S nodejs && \ adduser -S nextjs -u 1001 WORKDIR /app COPY --from=builder /app/node_modules ./node_modules COPY --chown =nextjs:nodejs server.js . COPY --chown =nextjs:nodejs package*.json ./ USER nextjs EXPOSE 3000 HEALTHCHECK --interval=30s --timeout =3s --start-period=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 CMD ["node" , "server.js" ] EOF docker build -t nodejs-app . docker run -d --name nodeapp -p 3000:3000 -e NODE_ENV=production nodejs-app sleep 5curl http://localhost:3000 curl http://localhost:3000/health docker images nodejs-app docker stop nodeapp docker rm nodeapp
5.4 构建优化技巧
使用 .dockerignore
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 cat > .dockerignore << 'EOF' .git .gitignore README.md docs/ node_modules/ __pycache__/ *.pyc .vscode/ .idea/ .DS_Store Thumbs.db *.log logs/ test /tests/ *.test dist/ build/ target/ EOF
docker 在构建镜像过程中,会忽略掉 .dockerignore 文件中指定的文件和目录。
层缓存优化
1 2 3 4 5 6 7 8 9 10 11 12 FROM node:18 -alpineCOPY . /app WORKDIR /app RUN npm install FROM node:18 -alpineWORKDIR /app COPY package*.json ./ RUN npm install COPY . .
后者的做法利用了 Docker 的层缓存机制,只有在依赖配置文件(package.json 或 requirements.txt)发生变化时才会重新安装依赖,而业务代码的变化不会触发依赖安装。
1 2 3 4 5 FROM node:18 -alpineWORKDIR /app COPY package*.json ./ RUN npm install COPY . .
减少镜像层数
1 2 3 4 5 6 7 8 9 10 11 RUN apt-get update RUN apt-get install -y curl RUN apt-get install -y git RUN apt-get clean RUN apt-get update && \ apt-get install -y curl git && \ apt-get clean && \ rm -rf /var/lib/apt/lists/*
5.5 构建上下文和高级技巧
构建参数 (ARG)
1 2 3 4 5 6 7 8 9 10 ARG NODE_VERSION=18 FROM node:${NODE_VERSION}-alpineARG BUILD_DATEARG VERSIONLABEL build_date=${BUILD_DATE} LABEL version=${VERSION}
留意 ARG 和 ENV 使用场景的区别:
ARG = Argument(参数)→ 构建时的"参数",构建时用完就扔
ENV = Environment(环境)→ 运行时的"环境变量",运行时也能用
多平台构建
1 2 3 4 5 6 7 8 docker buildx create --name multiplatform --use docker buildx build --platform linux/amd64,linux/arm64 -t my-app:latest . docker buildx build --platform linux/amd64,linux/arm64 -t my-app:latest --push .
注:大多数容器化应用都是 Linux 容器,通过 Docker Desktop 使用 manifest list (多架构清单) 来实现跨平台支持。
构建缓存
1 2 3 4 5 6 7 8 docker build --cache-from my-app:latest -t my-app:new . docker build --no-cache -t my-app . docker history my-app
5.6 安全最佳实践
使用非 root 用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 FROM alpine:latestRUN addgroup -g 1001 -S appgroup && \ adduser -u 1001 -S appuser -G appgroup WORKDIR /app RUN chown appuser:appgroup /app USER appuserCOPY --chown =appuser:appgroup . .
最小化攻击面
1 2 3 4 5 6 7 8 9 10 11 FROM alpine:latestRUN apk add --no-cache ca-certificates RUN rm -rf /var/cache/apk/* /tmp/* FROM node:18.17 .0 -alpine
本章总结
在本章中,我们深入学习了 Dockerfile 编写和镜像构建:
Dockerfile 基础 :掌握了 Dockerfile 的基本语法和常用指令
指令详解 :深入理解了 FROM、RUN、COPY、WORKDIR、ENV、EXPOSE、CMD、ENTRYPOINT 等指令
实践练习 :通过 Python 和 Node.js 应用构建加深理解
构建优化 :学会了使用 .dockerignore、层缓存、减少层数等优化技巧
高级技巧 :了解了构建参数、多平台构建、构建缓存等高级特性
安全实践 :掌握了非 root 用户、最小化攻击面等安全最佳实践
关键概念总结 :
多阶段构建 :减少最终镜像大小,分离构建和运行环境
层缓存 :合理安排指令顺序,提高构建效率
构建上下文 :理解 Docker 构建过程中的文件传输机制
镜像优化 :通过各种技巧减少镜像大小和提高安全性
下一章我们将学习 Docker Compose,实现多容器应用的编排和管理。
第6章:Docker Compose 多容器编排
6.1 Docker Compose 简介
Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过 YAML 文件配置应用的服务,然后使用单个命令创建并启动所有服务。
为什么需要 Docker Compose
1 2 3 4 5 6 7 8 docker network create app-network docker run -d --name database --network app-network -e MYSQL_ROOT_PASSWORD=root mysql docker run -d --name redis --network app-network redis docker run -d --name web --network app-network -p 8080:80 nginx docker-compose up -d
安装 Docker Compose
1 2 3 4 5 6 7 8 9 10 11 12 docker-compose --version sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s) -$(uname -m) " -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose docker-compose --version
6.2 Docker Compose 文件结构
基本语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 version: '3.8' services: service_name: image: image_name ports: - "host_port:container_port" environment: - ENV_VAR=value volumes: - host_path:container_path networks: network_name: volumes: volume_name:
6.3 Compose 文件详解
服务配置选项
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 version: '3.8' services: app: image: nginx:alpine build: context: . dockerfile: Dockerfile args: - BUILD_ARG=value container_name: my-app ports: - "8080:80" - "443:443" environment: - NODE_ENV=production - DEBUG=false env_file: - .env - .env.local volumes: - ./data:/app/data - app_logs:/app/logs networks: - frontend - backend depends_on: - database - redis restart: unless-stopped deploy: resources: limits: memory: 512M cpus: '0.5' healthcheck: test: ["CMD" , "curl" , "-f" , "http://localhost" ] interval: 30s timeout: 10s retries: 3
这里包括几个关键概念:
image :使用的镜像名称(必填,除非使用 build 构建)
build :构建镜像的上下文和 Dockerfile 路径
container_name :容器名称,(可选,容器的唯一标识,默认为 {项目名}_{服务名}_{序号}
)
ports :端口映射
environment :环境变量
env_file :环境变量文件(默认读取 .env
文件)
volumes :数据卷挂载
networks :网络连接
depends_on :依赖服务(可选,确保服务启动顺序)
restart :重启策略(默认 no
,可选 always
、on-failure
、unless-stopped
)
deploy :用于配置资源约束****、副本数量 和健康检查 等部署相关设置。
网络配置
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 version: '3.8' services: web: image: nginx networks: - frontend api: image: node:alpine networks: - frontend - backend database: image: mysql networks: - backend networks: frontend: driver: bridge backend: driver: bridge internal: true
此外,可以通过 external: true
参数来指定外部已存在的网络。留意二者的区别:
internal: true
:只能和同一网络内的其他容器通信,无法访问外网。
external: true
:声明这是一个已经存在的外部网络,在 docker-compose down 时不会删除这个网络。
数据卷配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 version: '3.8' services: app: image: nginx volumes: - app_data:/app/data - ./config:/app/config:ro - /tmp:/app/tmp volumes: app_data: driver: local external_volume: external: true
6.4 Compose 命令详解
基本命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 docker-compose up docker-compose up -d docker-compose up --build docker-compose up service_name docker-compose stop docker-compose stop service_name docker-compose down docker-compose down -v docker-compose ps docker-compose logs docker-compose logs -f service_name docker-compose exec service_name command docker-compose run service_name command docker-compose up -d --scale web=3
配置管理
1 2 3 4 5 6 7 8 9 10 11 12 docker-compose config docker-compose -f docker-compose.yml -f docker-compose.prod.yml up docker-compose -p myproject up export COMPOSE_PROJECT_NAME=myappdocker-compose up
6.6 高级特性
服务扩展和负载均衡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 version: '3.8' services: nginx: image: nginx:alpine ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf depends_on: - web web: build: . expose: - "3000" environment: - NODE_ENV=production database: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=rootpass
1 2 3 4 5 6 7 8 9 docker-compose up -d --scale web=3 upstream backend { server web_1:3000; server web_2:3000; server web_3:3000; }
健康检查和依赖管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 version: '3.8' services: web: image: nginx healthcheck: test: ["CMD" , "curl" , "-f" , "http://localhost" ] interval: 30s timeout: 10s retries: 3 start_period: 40s depends_on: api: condition: service_healthy api: build: . healthcheck: test: ["CMD" , "curl" , "-f" , "http://localhost:3000/health" ] interval: 30s timeout: 10s retries: 3
本章总结
在本章中,我们全面学习了 Docker Compose 多容器编排:
Compose 基础 :理解了 Docker Compose 的作用和基本概念
文件结构 :掌握了 docker-compose.yml 的语法和配置选项
服务配置 :学会了配置服务、网络、数据卷等各种选项
实践应用 :通过完整的 Web 应用栈和开发环境配置加深理解
命令操作 :掌握了 Compose 的各种命令和使用技巧
高级特性 :了解了服务扩展、负载均衡、健康检查等高级功能
Compose vs 手动管理对比 :
简化操作 :一个命令启动整个应用栈
配置管理 :声明式配置,易于版本控制
环境一致性 :确保开发、测试、生产环境一致
服务发现 :自动的服务名称解析
扩展性 :轻松扩展服务实例数量
最后一章我们将学习 Docker 镜像管理和仓库操作,包括镜像的推送、拉取、私有仓库搭建等内容。
第7章:Docker 镜像管理和仓库操作
7.1 Docker 镜像管理基础
镜像的生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 构建 -> 标记 -> 推送 -> 拉取 -> 运行 -> 删除 docker images docker image ls docker image inspect nginx:alpine docker image history nginx:alpine docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
镜像标记和命名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [registry_host[:port]/]username/repository[:tag] docker.io/library/nginx:latest docker.io/username/myapp:v1.0 registry.example.com/team/app:latest docker tag nginx:alpine myregistry.com/nginx:v1.0 docker tag myapp:latest myapp:v1.0 docker tag myapp:latest myapp:production docker images myapp
镜像清理和优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 docker rmi nginx:alpine docker image rm nginx:alpine docker rmi $(docker images -q ubuntu) docker image prune docker image prune -a docker image prune -a --filter "until=24h" docker system df docker system prune -a --volumes
7.2 Docker Hub 操作
Docker Hub 基本操作
1 2 3 4 5 6 7 8 docker login docker login registry.example.com cat ~/.docker/config.json
注意,这里用户名的大小写敏感。一般地,建议在设置页面创建 token,通过 token 登录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 docker search nginx docker search --limit 5 --filter stars=100 nginx docker pull nginx docker pull nginx:1.21-alpine docker pull ubuntu:20.04 docker build -t username/myapp:v1.0 . docker push username/myapp:v1.0 docker logout
上边命令中的 push
镜像,以及 pull
私人镜像需要登录。
实践:发布自己的镜像
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 mkdir -p /tmp/docker-tutorial/my-web-appcd /tmp/docker-tutorial/my-web-appcat > app.py << 'EOF' from flask import Flask, jsonify import os import socket app = Flask(__name__) @app.route('/' ) def hello(): return jsonify({ 'message' : 'Hello from my Docker app!' , 'hostname' : socket.gethostname(), 'version' : os.environ.get('APP_VERSION' , '1.0.0' ) }) @app.route('/health' ) def health(): return jsonify({'status' : 'healthy' }) if __name__ == '__main__' : app.run(host='0.0.0.0' , port=5000) EOF cat > requirements.txt << 'EOF' Flask==2.3.3 EOF cat > Dockerfile << 'EOF' FROM python:3.11-alpine WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app.py . EXPOSE 5000 ENV APP_VERSION=1.0.0 CMD ["python" , "app.py" ] EOF docker build -t username/my-web-app:1.0.0 . docker build -t username/my-web-app:latest . docker run -d -p 5000:5000 --name test-app username/my-web-app:1.0.0 curl http://localhost:5000 curl http://localhost:5000/health docker stop test-app docker rm test-app
7.3 私有镜像仓库
搭建本地 Registry
关于镜像站,我们之前详细讲过一期,可以参考 『