安装 官方文档
配置 apt 仓库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 sudo apt updatesudo apt install -y ca-certificates curlsudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/debian/gpg \ -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.ascsudo tee /etc/apt/sources.list.d/docker.sources <<EOF Types: deb URIs: https://download.docker.com/linux/debian Suites: $(. /etc/os-release && echo "$VERSION_CODENAME") Components: stable Architectures: $(dpkg --print-architecture) Signed-By: /etc/apt/keyrings/docker.asc EOF sudo apt update
安装 1 2 3 4 5 6 7 8 9 10 11 sudo apt install -y docker-ce docker-ce-cli containerd.io \ docker-buildx-plugin docker-compose-plugin sudo apt list --all-versions docker-ceVERSION_STRING=5:29.5.3-1~debian.12~bookworm sudo apt install -y \ docker-ce=$VERSION_STRING \ docker-ce-cli=$VERSION_STRING \ containerd.io docker-buildx-plugin docker-compose-plugin
启动与验证 1 2 3 4 5 6 sudo systemctl enable dockersudo systemctl restart dockersudo systemctl status dockerdocker version sudo docker run hello-world
非 root 用户免 sudo 1 2 sudo usermod -aG docker $USER
daemon.json 配置 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 sudo install -d /etc/dockersudo tee /etc/docker/daemon.json >/dev/null <<'EOF' { "log-driver" : "json-file" , "log-opts" : { "max-size" : "50m" , "max-file" : "3" }, "live-restore" : true , "ipv6" : false , "dns" : ["1.1.1.1" , "8.8.8.8" ], "exec-opts" : ["native.cgroupdriver=systemd" ], "features" : { "buildkit" : true }, "bip" : "172.16.0.1/24" , "default-address-pools" : [ { "base" : "172.26.0.0/16" , "size" : 24 } ] } EOF sudo systemctl restart dockerdocker info | sed -n '1,80p'
容器与镜像基础操作 镜像操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 docker pull <镜像名> docker pull <镜像名>:<版本> docker images docker rmi <镜像名> docker history <镜像名>:<版本> docker search <关键词> docker tag <源镜像>:<源tag> <目标镜像>:<目标tag>
容器生命周期 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 docker run <镜像名> docker run -d \ --name <容器名> \ -p <宿主端口>:<容器端口> \ -v <宿主路径>:<容器路径> \ -e KEY=VALUE \ --network <网络名> \ --restart unless-stopped \ <镜像名> docker create <镜像名> docker run -it <镜像名> /bin/bash docker start <容器名/ID> docker stop <容器名/ID> docker stop -t 30 <容器名/ID> docker kill <容器名/ID> docker restart <容器名/ID> docker run --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 36 37 docker ps docker ps -a docker inspect <容器名/镜像名> docker exec -it <容器名/ID> /bin/bash docker exec <容器名/ID> cat /etc/os-release docker logs <容器名/ID> docker logs -f <容器名/ID> docker logs --tail 100 <容器名/ID> docker top <容器名/ID> docker port <容器名/ID> docker cp <本地路径> <容器名>:<容器路径> docker cp <容器名>:<容器路径> <本地路径> docker rm <容器名/ID> docker rm -f <容器名/ID>
镜像导入导出 1 2 3 4 5 6 7 8 9 10 11 docker save -o <文件名>.tar <镜像名>:<tag> docker load -i <文件名>.tar docker export -o <文件名>.tar <容器名/ID> docker import <文件名>.tar <镜像名>:<tag>
推送镜像到 Docker Hub 1 2 3 4 5 6 7 8 9 10 11 docker login -u <用户名> docker tag <本地镜像> <用户名>/<仓库名>:<版本> docker push <用户名>/<仓库名>:<版本> docker logout
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 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 FROM <基础镜像>:<tag>FROM scratchLABEL maintainer="name <email>" LABEL version="1.0" description="示例镜像" WORKDIR /app ARG BUILD_VERSION=1.0 ENV APP_ENV=productionENV DB_HOST=localhost \ DB_PORT=5432 COPY <源路径> <目标路径> COPY . /app COPY --chown =1000:1000 . /app ADD https://example.com/file.tar.gz /tmp/ ADD app.tar.gz /app/ RUN apt update && \ apt install -y --no-install-recommends \ curl wget && \ rm -rf /var/lib/apt/lists/* EXPOSE 8080 EXPOSE 8080 /tcpEXPOSE 5353 /udpCMD ["nginx" , "-g" , "daemon off;" ] ENTRYPOINT ["python" ] CMD ["app.py" ] VOLUME ["/data" ] USER 1000 :1000 HEALTHCHECK --interval=30s --timeout =10s --start-period=10s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1 HEALTHCHECK NONE
实用 Dockerfile 示例 1 2 3 4 5 6 7 8 9 10 11 12 13 FROM golang:1.22 -alpine AS builderWORKDIR /build COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -o app . FROM debian:12 -slimWORKDIR /app COPY --from=builder /build/app . EXPOSE 8080 CMD ["./app" ]
1 2 3 4 5 6 7 8 FROM python:3.12 -slimWORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD ["python" , "-m" , "uvicorn" , "main:app" , "--host" , "0.0.0.0" ]
.dockerignore 1 2 3 4 5 6 7 8 # 忽略不需要打包的文件,减少构建上下文体积 .git .gitignore __pycache__ *.pyc node_modules * .log.env
构建命令 1 2 3 4 5 6 7 8 9 10 11 12 docker build -t <镜像名>:<tag> <构建目录> docker build -t myapp:1.0 . docker build -f Dockerfile.prod -t myapp:prod . docker build --build-arg BUILD_VERSION=2.0 -t myapp . docker build --no-cache -t myapp .
数据卷与持久化存储 Docker 容器的文件系统是临时的,容器删除后数据丢失,通过数据卷实现持久化
存储类型对比
类型
命令形式
数据位置
适用场景
volume
-v <卷名>:<容器路径>
Docker 管理(/var/lib/docker/volumes/)
生产数据持久化(推荐)
bind mount
-v <宿主绝对路径>:<容器路径>
宿主机指定目录
挂载配置文件、开发时挂载源码
tmpfs
--tmpfs <容器路径>
内存(重启丢失)
敏感数据临时存储
Volume 操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker volume create <卷名> docker volume ls docker volume inspect <卷名> docker volume rm <卷名> docker volume prune
挂载示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 docker run -d \ --name postgres \ -v pgdata:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=secret \ postgres:16 docker run -d \ --name nginx \ -v /opt/nginx/html:/usr/share/nginx/html:ro \ -p 80:80 \ nginx docker run -d \ --tmpfs /tmp:size=100m \ myapp
数据备份与恢复 1 2 3 4 5 6 7 8 9 10 11 12 13 docker run --rm \ -v pgdata:/data \ -v $(pwd ):/backup \ debian:12 \ tar czf /backup/pgdata_backup.tar.gz -C /data . docker run --rm \ -v pgdata:/data \ -v $(pwd ):/backup \ debian:12 \ tar xzf /backup/pgdata_backup.tar.gz -C /data
容器网络管理 网络类型
网络类型
说明
适用场景
bridge
默认网络,容器间通过 IP 通信
默认隔离
host
共享宿主机网络栈
高性能、减少 NAT 开销
none
仅 loopback,完全隔离
无网络需求的任务
自定义 bridge
容器间可用容器名 作为域名互相访问
生产推荐
自定义 bridge 与默认 bridge 的核心区别:加入同一自定义网络的容器可以直接用容器名 互相访问(内置 DNS 解析),默认 bridge 只能用 IP
网络操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 docker network create <网络名> docker network create --driver bridge \ --subnet 192.168.100.0/24 \ --gateway 192.168.100.1 \ mynet docker network inspect <网络名> docker network rm <网络名> docker network prune
端口映射 1 2 3 4 5 6 7 8 9 10 11 docker run -p <宿主端口>:<容器端口> <镜像> docker run -p 127.0.0.1:8080:80 <镜像> docker run -P <镜像> docker port <容器名/ID>
将容器加入/离开网络 1 2 3 4 5 6 7 8 9 10 11 docker network connect <网络名> <容器名/ID> docker network disconnect <网络名> <容器名/ID> docker run --network <网络名> <镜像> docker run --network mynet --network-alias db <镜像>
容器间通信示例 1 2 3 4 5 6 7 8 9 10 11 12 docker network create appnet docker run -d --name postgres --network appnet \ -e POSTGRES_PASSWORD=secret postgres:16 docker run -d --name app --network appnet \ -e DB_HOST=postgres \ -p 8080:8080 \ myapp
Docker Compose 官方文档
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 services: WebApp: image: nginx:alpine container_name: WebApp restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./html:/usr/share/nginx/html:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro environment: - TZ=Asia/Shanghai env_file: - .env networks: - AppNet depends_on: Database: condition: service_healthy healthcheck: test: ["CMD" , "curl" , "-f" , "http://localhost" ] interval: 30s timeout: 10s retries: 3 Database: image: postgres:16 container_name: Database restart: unless-stopped volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_DB: ${DB_NAME} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} networks: - AppNet healthcheck: test: ["CMD-SHELL" , "pg_isready -U ${DB_USER} -d ${DB_NAME}" ] interval: 10s timeout: 5s retries: 5 start_period: 30s networks: AppNet: driver: bridge name: AppNet volumes: pgdata: name: pgdata
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 docker compose up -d docker compose up -d WebApp docker compose down docker compose down -v docker compose down --rmi all docker compose up -d --build docker compose ps docker compose logs docker compose logs -f WebApp docker compose exec WebApp /bin/sh docker compose restart WebApp docker compose pull docker compose config
.env 文件示例 1 2 3 4 5 DB_NAME=myapp DB_USER=appuser DB_PASSWORD=supersecret REDIS_PASSWORD=anothersecret
多环境配置 1 2 3 4 5 docker compose -f compose.yaml -f compose.dev.yaml up -d docker compose --env-file .env.prod up -d
资源限制 防止单个容器耗尽宿主机资源
1 2 3 4 5 6 7 8 9 10 11 12 docker run --memory 512m <镜像> docker run --memory 512m --memory-swap 1g <镜像> docker run --cpus 1.5 <镜像> docker run --cpu-shares 512 <镜像> docker stats docker stats <容器名> docker stats --no-stream
Compose 中设置资源限制 1 2 3 4 5 6 7 8 9 10 11 services: App: image: myapp deploy: resources: limits: cpus: "1.0" memory: 512M reservations: cpus: "0.25" memory: 128M
日志与监控 日志管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 docker logs <容器名> docker logs -f <容器名> docker logs --tail 200 <容器名> docker logs -t <容器名> docker logs -f --tail 100 -t <容器名> docker logs --since 2024-01-01T00:00:00 <容器名> docker logs --since 1h <容器名>
daemon.json 中已配置日志轮转(max-size: 50m,max-file: 3),日志文件实际位于:
1 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log
资源监控 1 2 3 4 5 6 7 8 9 docker stats docker stats <容器名1> <容器名2> docker stats --no-stream --format \ "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
容器状态信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker inspect <容器名> docker inspect --format '{{.State.Status}}' <容器名> docker inspect --format '{{.NetworkSettings.IPAddress}}' <容器名> docker inspect --format \ '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <容器名> docker top <容器名> docker diff <容器名>
清理与维护 日常清理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 docker container prune docker image prune docker image prune -a docker network prune docker volume prune docker system prune docker system prune --volumes
查看磁盘占用 1 2 docker system df docker system df -v
升级容器 1 2 3 4 5 6 7 8 9 docker pull <镜像名>:<tag> docker stop <容器名> docker rm <容器名> docker run -d ...(原来的参数) docker compose pull docker compose up -d
重启策略详解 通过 --restart 参数或 Compose 的 restart 字段控制容器异常退出后的行为
策略对比
策略
说明
适用场景
no
不自动重启(默认)
一次性任务、调试
always
总是重启,包括 Docker 服务重启后
需要随 Docker 启动的服务
on-failure[:N]
仅在退出码非 0 时重启,可限制次数
允许正常退出、防止无限循环重启
unless-stopped
总是重启,但手动docker stop 后不恢复
生产服务推荐
关键区别 always vs unless-stopped :
always:即使你手动 docker stop 了容器,下次 Docker 服务重启(如服务器重启)后,容器依然会被拉起
unless-stopped:手动 docker stop 后,Docker 服务重启也不会 自动拉起,尊重你的手动操作
生产环境推荐 unless-stopped,需要维护时 docker stop 后不会被意外恢复
on-failure :
1 2 docker run --restart on-failure:3 <镜像>
适合启动脚本、数据库迁移等任务:成功退出(exit 0)不重启,失败时最多重试 N 次
设置与修改 1 2 3 4 5 6 7 8 docker run --restart unless-stopped <镜像> docker update --restart unless-stopped <容器名/ID> docker inspect --format '{{.HostConfig.RestartPolicy.Name}}' <容器名>
健康检查与启动依赖 为什么需要健康检查 depends_on 默认只等待容器启动 ,不等待服务就绪 数据库容器启动后还需要几秒初始化,此时应用容器若已尝试连接会失败 通过健康检查 + condition: service_healthy 解决此问题
Dockerfile 中定义健康检查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 HEALTHCHECK --interval=15s --timeout =5s --start-period=10s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1 HEALTHCHECK --interval=10s --timeout =3s --retries=5 \ CMD nc -z localhost 5432 || exit 1 HEALTHCHECK NONE
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 services: Database: image: postgres:16 healthcheck: test: ["CMD-SHELL" , "pg_isready -U ${DB_USER} -d ${DB_NAME}" ] interval: 10s timeout: 5s retries: 5 start_period: 30s Redis: image: redis:7-alpine healthcheck: test: ["CMD" , "redis-cli" , "ping" ] interval: 10s timeout: 3s retries: 3 App: image: myapp depends_on: Database: condition: service_healthy Redis: condition: service_healthy
depends_on 条件类型
条件
说明
service_started
默认,仅等待容器启动(不等待就绪)
service_healthy
等待健康检查通过后才启动当前服务
service_completed_successfully
等待依赖服务正常退出(exit 0),适合 migration 任务
查看健康状态 1 2 3 4 5 docker ps docker inspect --format '{{json .State.Health}}' <容器名> | python3 -m json.tool
容器时区设置 容器默认使用 UTC,如果宿主机是 Asia/Shanghai 而容器是 UTC,日志时间会相差 8 小时
方法一:环境变量(推荐,适用于大多数镜像) 1 docker run -e TZ=Asia/Shanghai <镜像>
Compose:
1 2 3 4 services: App: environment: - TZ=Asia/Shanghai
方法二:挂载宿主机时区文件 1 2 3 4 docker run \ -v /etc/localtime:/etc/localtime:ro \ -v /etc/timezone:/etc/timezone:ro \ <镜像>
Compose:
1 2 3 4 5 services: App: volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro
方法三:Dockerfile 中固化时区 1 2 3 4 5 FROM debian:12 -slimRUN apt update && \ apt install -y --no-install-recommends tzdata && \ rm -rf /var/lib/apt/lists/* ENV TZ=Asia/Shanghai
验证
私有镜像仓库 团队内部使用,避免镜像上传到公网,同时加快拉取速度
官方文档
方案一:官方 Registry(轻量,个人 / 小团队) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 mkdir -p /opt/Registrycat > /opt/Registry/compose.yaml <<'EOF' services: Registry: image: registry:2 container_name: Registry restart: unless-stopped ports: - "5000:5000" volumes: - ./data:/var/lib/registry environment: - REGISTRY_STORAGE_DELETE_ENABLED=true EOF cd /opt/Registrydocker compose up -d
1 2 3 4 5 6 docker tag myapp:1.0 <仓库IP>:5000/myapp:1.0 docker push <仓库IP>:5000/myapp:1.0 docker pull <仓库IP>:5000/myapp:1.0
如果仓库没有 HTTPS,需要在客户端的 daemon.json 中添加:
1 2 3 { "insecure-registries" : [ "<仓库IP>:5000" ] }
方案二:Harbor(企业级,含权限管理、漏洞扫描) Harbor 功能完整但部署较重,参考官方安装文档:https://goharbor.io/docs/latest/install-config/
登录私有仓库 1 docker login <仓库地址>:<端口> -u <用户名>
多平台构建 buildx 用于在 x86 机器上构建 ARM 镜像,或同时发布支持多架构的镜像
官方文档
准备工作 1 2 3 4 5 6 7 8 9 docker buildx ls docker buildx create --name multiarch --use docker buildx inspect --bootstrap docker run --privileged --rm tonistiigi/binfmt --install all
构建并推送 1 2 3 4 5 6 7 8 9 10 11 12 13 docker buildx build \ --platform linux/amd64,linux/arm64,linux/arm/v7 \ -t <用户名>/<镜像名>:<tag> \ --push \ . docker buildx build \ --platform linux/amd64 \ -t myapp:1.0 \ --load \ .
查看镜像支持的平台 1 docker buildx imagetools inspect <镜像名>:<tag>
Docker Context 远程管理 不需要 SSH 进入远程服务器,直接在本地用 docker 命令管理远端 Docker
原理 Docker CLI 通过 Context 切换连接目标,默认连接本机的 /var/run/docker.sock,切换 context 后所有命令都在远端执行
创建远程 Context 1 2 3 4 5 6 7 docker context create <context名> \ --docker "host=ssh://root@<远程IP>:<端口>" docker context create aliyun-gz \ --docker "host=ssh://root@10.144.144.1:48237"
管理 Context 1 2 3 4 5 6 7 8 9 10 11 docker context ls docker context use <context名> docker context use default docker context rm <context名>
单次使用远程 Context(不切换默认) 1 2 docker --context aliyun-gz ps docker --context aliyun-gz compose up -d
注意事项
使用 SSH context 需要本地能 SSH 免密登录远端(密钥认证)
docker compose 命令同样支持 context,但构建时上下文仍在本地,大项目传输慢
Secrets 管理 .env 文件的局限 .env 文件中的值会以明文环境变量注入容器,通过 docker inspect 可以直接看到所有环境变量值,存在泄漏风险 Secrets 将敏感数据以文件形式挂载到容器内 /run/secrets/<secret名>,不出现在环境变量中
Compose secrets 用法 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 services: Database: image: postgres:16 container_name: Database restart: unless-stopped environment: POSTGRES_DB: myapp POSTGRES_USER: appuser POSTGRES_PASSWORD_FILE: /run/secrets/db_password secrets: - db_password networks: - AppNet App: image: myapp secrets: - db_password - api_key secrets: db_password: file: ./secrets/db_password.txt api_key: file: ./secrets/api_key.txt networks: AppNet: name: AppNet
创建 secret 文件 1 2 3 4 5 mkdir -p ./secretsprintf 'supersecretpassword' > ./secrets/db_password.txtprintf 'sk-xxxxxxxxxxxx' > ./secrets/api_key.txtchmod 600 ./secrets/*.txt
将 secrets/ 目录加入 .gitignore:
在容器内读取 secret 应用代码读取文件而非环境变量:
1 2 3 with open ('/run/secrets/db_password' ) as f: db_password = f.read().strip()
1 2 3 4 import "os" data, _ := os.ReadFile("/run/secrets/db_password" ) dbPassword := string (data)
验证 secret 未暴露在环境变量中 1 2 3 4 5 docker inspect --format '{{json .Config.Env}}' <容器名> docker exec <容器名> cat /run/secrets/db_password