当前位置: 首页 > news >正文

Docker完整学习笔记

1. 初识 Docker

核心考点:Docker 解决啥、和虚拟机的区别、架构三件套

💡 面试被问"Docker 为啥比 VM 轻",答共享内核 + 无 Guest OS​ 就够,别扯 cgroup/namespace 太细,除非对方追问。

2. 镜像加速

镜像加速本质改/etc/docker/daemon.jsonregistry-mirrors

2026还能正常访问的

​ { "registry-mirrors": [ "https://docker.1ms.run", "https://docker.xuanyuan.me", "https://docker.m.daocloud.io" ] } ​

3. Docker 基本操作

常用命令
# ========== 镜像管理 ========== # 列出本地镜像 docker images # 拉取镜像 docker pull nginx:1.20 # 删除镜像 docker rmi nginx:1.20 # 导出镜像为tar文件 docker save -o nginx.tar nginx:1.20 # 从tar文件导入镜像 docker load -i nginx.tar # 查看镜像历史分层 docker history nginx:1.20 # 标记镜像(打标签) docker tag nginx:1.20 myrepo/nginx:1.20 # 推送镜像到仓库 docker push myrepo/nginx:1.20 # ========== 容器生命周期 ========== # 创建并启动容器(前台) docker run -it --name ubuntu ubuntu:22.04 /bin/bash # 创建并启动容器(后台) docker run -d --name nginx -p 80:80 nginx:1.20 # 启动已有容器 docker start nginx # 停止容器 docker stop nginx # 重启容器 docker restart nginx # 强制停止容器 docker kill nginx # 暂停容器 docker pause nginx # 恢复暂停的容器 docker unpause nginx # 删除容器(运行中需加-f) docker rm nginx # 强制删除运行中的容器 docker rm -f nginx # 删除所有停止的容器 docker container prune # ========== 容器操作 ========== # 查看运行中的容器 docker ps # 查看所有容器(含停止) docker ps -a # 查看容器详细信息(JSON) docker inspect nginx # 查看容器日志(实时跟踪) docker logs -f nginx # 进入容器执行命令(交互式) docker exec -it nginx /bin/bash # 在容器内执行单条命令 docker exec nginx ls /etc # 从宿主机复制文件到容器 docker cp /path/host.txt nginx:/container/path # 从容器复制文件到宿主机 docker cp nginx:/container/path /path/host.txt # 查看容器内进程 docker top nginx # 查看容器资源占用 docker stats nginx # 查看容器端口映射 docker port nginx # 重命名容器 docker rename old-name new-name # ========== 数据卷 ========== # 创建命名卷 docker volume create my-volume # 列出所有卷 docker volume ls # 查看卷详情 docker volume inspect my-volume # 删除卷 docker volume rm my-volume # 删除未使用的卷 docker volume prune # 挂载命名卷运行容器 docker run -d --name mysql -v my-volume:/var/lib/mysql mysql:8.0 # 挂载宿主机目录(bind mount) docker run -d --name nginx -v /host/html:/usr/share/nginx/html nginx:1.20 # ========== 网络 ========== # 列出网络 docker network ls # 创建桥接网络 docker network create my-net # 查看网络详情 docker network inspect my-net # 连接容器到网络 docker network connect my-net nginx # 断开容器与网络 docker network disconnect my-net nginx # 删除网络 docker network rm my-net # 删除未使用的网络 docker network prune # 指定网络运行容器 docker run -d --name app --network my-net my-app # ========== Docker Compose ========== # 启动服务(后台) docker-compose up -d # 启动服务并重新构建镜像 docker-compose up -d --build # 停止服务 docker-compose stop # 停止并删除容器、网络(默认不删卷) docker-compose down # 停止并删除容器、网络、卷(危险) docker-compose down -v # 查看服务状态 docker-compose ps # 查看服务日志 docker-compose logs -f app # 重启服务 docker-compose restart # 拉取最新镜像 docker-compose pull # 执行服务中的命令 docker-compose exec app /bin/bash # ========== 清理与系统信息 ========== # 查看Docker版本 docker version # 查看Docker系统信息 docker info # 查看磁盘使用情况 docker system df # 清理所有未使用的资源(容器、镜像、网络、卷) docker system prune -a --volumes # 清理未使用的镜像 docker image prune -a # 清理未使用的容器 docker container prune # 清理未使用的网络 docker network prune # 清理未使用的卷 docker volume prune # 查看事件流(实时监控) docker events # 查看历史命令 docker history nginx:1.20
容器备份恢复

将一台机器上的容器备份恢复到另一台机器

# ========== 场景A:无状态容器(如 Spring Boot 镜像)→ save/load ========== # 【原机器】1. 提交容器为镜像(如果当初是 docker run 起的、没 save 过镜像) docker commit sb-container sb-app:1.0 # 【原机器】2. 导出镜像为 tar docker save -o sb-app.tar sb-app:1.0 # 【原机器】3. 连同 docker-compose.yml 一起拷到新机器 scp sb-app.tar user@new-host:/opt/ scp docker-compose.yml user@new-host:/opt/ # 【新机器】4. 导入镜像 docker load -i /opt/sb-app.tar # 【新机器】5. 启动(前提:MySQL 等其他依赖已就位) docker-compose up -d # ========== 场景B:有状态容器(MySQL 数据卷)→ alpine tar 法 ========== # 【原机器】1. 停 MySQL 保一致性 docker stop mysql # 【原机器】2. alpine 临时容器把命名卷打成 tar docker run --rm \ -v mysql-data:/volume \ -v /tmp:/backup \ alpine \ tar -czf /backup/mysql-data.tar.gz -C /volume . # 【原机器】3. 拷到新机器 scp /tmp/mysql-data.tar.gz user@new-host:/tmp/ # 【新机器】4. 用同名 compose 先把卷创建出来(只起 mysql 让它初始化一次然后停) docker-compose up -d mysql docker-compose stop mysql # 【新机器】5. alpine 临时容器恢复卷数据 docker run --rm \ -v myapp_mysql-data:/volume \ -v /tmp:/backup \ alpine \ sh -c "rm -rf /volume/* && tar -xzf /backup/mysql-data.tar.gz -C /volume" # 【新机器】6. 起全套 docker-compose up -d # ========== 场景C:MySQL 跨版本/最稳 → mysqldump SQL 法 ========== # 【原机器】1. dump(--single-transaction 保证 InnoDB 一致性) docker exec mysql mysqldump -uroot -p${MYSQL_ROOT_PASSWORD} \ --single-transaction --routines --triggers --all-databases > /tmp/backup.sql # 【原机器】2. 拷 SQL + 镜像 + compose scp /tmp/backup.sql user@new-host:/tmp/ scp sb-app.tar user@new-host:/opt/ # 【新机器】3. load 镜像 + 起空 MySQL docker load -i /opt/sb-app.tar docker-compose up -d mysql # 此时库是空的 # 【新机器】4. 导入 SQL docker cp /tmp/backup.sql mysql:/tmp/ docker exec -i mysql mysql -uroot -p${MYSQL_ROOT_PASSWORD} < /tmp/backup.sql # 【新机器】5. 起应用 docker-compose up -d app # 【新机器】6. 验证 docker-compose ps curl http://localhost:8080/actuator/health
DockerFile和docker-compose.yml的用法案例

现在有个前后端分离项目:app.jar、dist(前端代码文件夹)、还用到了mysql、redis、nginx;

项目拆一下:5 样东西 ≠ 1 个 Dockerfile,Dockerfile 一次只构建一个镜像。正确拆法是:

一、后端 Dockerfile(app.jar)

如果用jdk8,将FROM eclipse-temurin:21-jre-alpine改为FROM eclipse-temurin:8-jre-alpine

# ========== 多阶段构建 ========== # 阶段1:构建(如果你的 CI 已经 mvn package 了,这段可以省,直接用阶段2) FROM maven:3.9-eclipse-temurin:21 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn clean package -DskipTests # 阶段2:运行 FROM eclipse-temurin:21-jre-alpine LABEL maintainer="you@example.com" # 时区(面试常问:为啥容器里时间不对) ENV TZ=Asia/Shanghai WORKDIR /app # 从构建阶段拷 jar(CI 已经打好就用下面这句替代上面阶段1) # COPY target/app.jar /app.jar COPY --from=build /app/target/*.jar app.jar # JVM 调优(8年经验简历能写"JVM 参数调优") # -Xms -Xmx 按容器内存来,比如容器 1G 就设 512m # UseContainerSupport 让 JVM 识别容器内存上限(JDK 8u191+ 默认开,21 肯定开) ENTRYPOINT ["java", \ "-Xms256m", "-Xmx512m", \ "-XX:+UseG1GC", \ "-Duser.timezone=Asia/Shanghai", \ "-jar", "/app.jar"]

💡 如果公司 CI 已经mvn package了,阶段1删掉,只留阶段2 +COPY target/app.jar /app.jar,镜像从 700MB 降到 80MB 级(alpine jre)。

二、 前端 Dockerfile(dist + nginx)

项目里dist/是 Vuenpm run build出来的,跟 nginx 放一起:

# ========== 多阶段构建 ========== # 阶段1:Node 编 dist(如果 dist 已经本地打好了,这段也可以省) FROM node:18-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci --registry=https://registry.npmmirror.com COPY . . RUN npm run build # 阶段2:Nginx 跑 dist FROM nginx:1.26-alpine # 删掉默认配置 RUN rm /etc/nginx/conf.d/default.conf # 拷自定义 nginx.conf(反向代理后端 api 用,下面给) COPY nginx.conf /etc/nginx/conf.d/ # 拷 dist(本地已有 dist 就 COPY dist /usr/share/nginx/html,不用阶段1) COPY --from=build /app/dist /usr/share/nginx/html EXPOSE 80

配套nginx.conf(解决前端路由 history 模式 + 反向代理/api到 Spring Boot):

server { listen 80; server_name localhost; # 前端静态资源 location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; # Vue Router history 模式必配 } # 反向代理后端接口 location /api/ { proxy_pass http://app:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }

注意proxy_pass http://app:8080里的app是 compose service 名,靠自定义网络 DNS 解析,不是 localhost。

三、docker-compose.yml 把 5 样串起来(重点交付物)
version: '3.8' services: # ===== 后端 ===== app: build: context: ./backend # 下放 app.jar + Dockerfile dockerfile: Dockerfile container_name: app ports: - "8080:8080" environment: SPRING_PROFILES_ACTIVE: prod SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/appdb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: root123 SPRING_DATA_REDIS_HOST: redis SPRING_DATA_REDIS_PORT: 6379 volumes: - ./logs:/app/logs # SB 日志挂出来 depends_on: - mysql - redis restart: always networks: - app-net # ===== 前端 + nginx ===== nginx: build: context: ./frontend # 下放 dist + nginx.conf + Dockerfile dockerfile: Dockerfile container_name: nginx ports: - "80:80" depends_on: - app restart: always networks: - app-net # ===== MySQL ===== mysql: image: mysql:8.0 container_name: mysql environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: appdb TZ: Asia/Shanghai ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql # 首次启动自动执行建表/初始化SQL(可选) # - ./init.sql:/docker-entrypoint-initdb.d/init.sql command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-authentication-plugin=mysql_native_password restart: always networks: - app-net # ===== Redis ===== redis: image: redis:7-alpine container_name: redis ports: - "6379:6379" volumes: - redis-data:/data # 自定义配置(可选,关保护模式/设密码) # - ./redis.conf:/etc/redis/redis.conf command: redis-server --appendonly yes restart: always networks: - app-net networks: app-net: driver: bridge volumes: mysql-data: redis-data:
四、目录结构参考(照着摆)
project/ ├── backend/ │ ├── Dockerfile # 后端的 │ ├── app.jar # mvn package 出来的 │ └── logs/ # 运行时挂出来 ├── frontend/ │ ├── Dockerfile # 前端的 │ ├── dist/ # npm run build 出来的 │ └── nginx.conf ├── docker-compose.yml └── init.sql # (可选) MySQL 初始化
五、启动 & 验证
# 构建 + 启动(--build 强制重打镜像,改了 Dockerfile 必加) docker-compose up -d --build # 看状态 docker-compose ps # 看后端日志 docker-compose logs -f app # 浏览器 http://服务器IP ,nginx 80 端口进,/api 反向代理到 app:8080
  1. 多阶段构建压镜像体积:Maven 3.9 + JDK21 编,Alpine JRE21 跑,最终镜像 80MB 级

  2. 镜像分层优化:pom.xml 单独 COPY 先dependency:go-offline,依赖层缓存

  3. nginx 反向代理解决跨域 + Vue history 模式try_files

  4. compose 自定义网络​ → 服务间用容器名互访,不用写 IP

  5. 有状态服务挂卷(mysql-data / redis-data),restart: always

⚠️ 一个坑:生产别把 mysql/redis 的ports暴露成"3306:3306",云服务器公网 3306 被扫很正常,改成"127.0.0.1:3306:3306"让 nginx→app→mysql 走内网就行。

4. Docker 核心概念

4.1 镜像 Image

镜像是容器运行的模板,里面包含应用程序、依赖库、配置文件、运行命令等。

特点:

  1. 镜像是只读的。
  2. 镜像是分层的。
  3. 镜像可以基于另一个镜像构建。
  4. 镜像可以上传到仓库,也可以从仓库拉取。

示例:

docker pull nginx:latest docker images

4.2 容器 Container

容器是镜像运行起来之后的实例。

特点:

  1. 一个镜像可以启动多个容器。
  2. 容器之间默认相互隔离。
  3. 容器删除后,容器可写层中的数据默认会丢失。
  4. 持久化数据应使用 volume 或 bind mount。

示例:

docker run -d --name my-nginx -p 8080:80 nginx docker ps docker stop my-nginx docker rm my-nginx

4.3 仓库 Registry

镜像仓库用于保存和分发镜像。

常见仓库:

  1. Docker Hub。
  2. 阿里云容器镜像服务。
  3. 腾讯云镜像仓库。
  4. Harbor 私有仓库。

常用命令:

docker login docker tag myapp:1.0 username/myapp:1.0 docker push username/myapp:1.0 docker pull username/myapp:1.0

AI写代码bash

5. Docker 安装

以下以 CentOS Stream 8 为例。

5.1 准备环境

实验环境:

  1. 容器管理工具:Docker Engine。
  2. 容器运行时:containerd、runc。
  3. 操作系统:CentOS Stream 8。
5.2 配置 Docker 软件源
yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

5.3 安装 Docker

yum install -y docker-ce docker-ce-cli containerd.io
5.4 启动 Docker
systemctl enable docker.service --now docker --version systemctl status docker
5.5 配置镜像加速
mkdir -p /etc/docker vim /etc/docker/daemon.json

示例配置:

{ "registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ] }

重启 Docker:

systemctl daemon-reload systemctl restart docker docker info

6. Docker 常用命令

6.1 镜像命令
# 查看本地镜像 docker images # 搜索镜像 docker search nginx # 拉取镜像 docker pull nginx:latest # 删除镜像 docker rmi nginx:latest # 查看镜像详细信息 docker inspect nginx # 查看镜像构建历史 docker history nginx

6.2 容器命令

# 创建并启动容器 docker run -d --name web -p 8080:80 nginx # 查看正在运行的容器 docker ps # 查看所有容器 docker ps -a # 停止容器 docker stop web # 启动已停止容器 docker start web # 重启容器 docker restart web # 删除容器 docker rm web # 强制删除运行中的容器 docker rm -f web
6.3 进入容器
docker exec -it web bash

如果容器中没有 bash,可以使用 sh:

docker exec -it web sh
6.4 查看日志
docker logs web docker logs -f web docker logs --tail 100 web
6.5 文件复制
# 从宿主机复制文件到容器 docker cp ./index.html web:/usr/share/nginx/html/index.html # 从容器复制文件到宿主机 docker cp web:/etc/nginx/nginx.conf ./nginx.conf
6.6 查看资源占用
docker stats
6.7 清理资源
# 删除停止的容器 docker container prune # 删除无用镜像 docker image prune # 删除无用网络 docker network prune # 删除无用 volume docker volume prune # 清理所有无用资源 docker system prune

注意:docker system prune -a会删除所有未被容器使用的镜像,生产环境慎用。

7. docker run 常用参数

docker run [OPTIONS] IMAGE [COMMAND]

常用参数:

参数作用
-d后台运行
-it交互式终端
--name指定容器名称
-p端口映射
-v挂载目录或数据卷
-e设置环境变量
--network指定网络
--restart设置重启策略
--rm容器退出后自动删除
--privileged开启特权模式
--memory限制内存
--cpus限制 CPU

示例:

docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -v mysql-data:/var/lib/mysql \ --restart=always \ mysql:8.0

8. Docker 网络

8.1 网络模式

Docker 常见网络模式:

网络模式说明
bridge默认模式,容器通过 docker0 网桥通信
host容器直接使用宿主机网络
none容器没有网络
container与另一个容器共享网络命名空间
自定义 bridge推荐用于多个容器互相通信
8.2 常用网络命令
# 查看网络 docker network ls # 查看网络详情 docker network inspect bridge # 创建自定义网络 docker network create app-net # 使用指定网络启动容器 docker run -d --name nginx --network app-net nginx # 将容器连接到网络 docker network connect app-net nginx # 将容器移出网络 docker network disconnect app-net nginx
8.3 容器之间通信

推荐使用自定义网络。处于同一个自定义网络中的容器,可以通过容器名互相访问。

示例:

docker network create app-net docker run -d --name redis --network app-net redis:7 docker run -it --rm --network app-net redis:7 redis-cli -h redis

9. Docker 存储

9.1 容器数据为什么会丢失

容器运行后会在镜像只读层上增加一层可写层。如果删除容器,这一层也会被删除。因此数据库、上传文件、日志等需要持久化的数据不能只放在容器内部。

9.2 volume 数据卷

volume 是 Docker 管理的数据卷,适合保存数据库数据。

# 创建数据卷 docker volume create mysql-data # 查看数据卷 docker volume ls # 查看数据卷详情 docker volume inspect mysql-data # 使用数据卷 docker run -d \ --name mysql8 \ -e MYSQL_ROOT_PASSWORD=123456 \ -v mysql-data:/var/lib/mysql \ mysql:8.0
9.3 bind mount 目录挂载

bind mount 是把宿主机目录挂载到容器中,适合挂载配置文件、项目代码。

docker run -d \ --name web \ -p 8080:80 \ -v /opt/nginx/html:/usr/share/nginx/html \ nginx
9.4 volume 与 bind mount 对比
对比项volumebind mount
管理方Docker 管理用户自己管理
路径Docker 默认路径用户指定路径
适用场景数据库、持久化数据配置文件、代码目录
可移植性较好依赖宿主机目录结构

10. Dockerfile

Dockerfile 是用来构建镜像的文本文件,里面定义了基础镜像、依赖安装、文件复制、启动命令等步骤。

10.1 常用指令
指令作用
FROM指定基础镜像
LABEL添加镜像元数据
WORKDIR指定工作目录
COPY复制文件到镜像
ADD复制文件,支持自动解压和 URL
RUN构建镜像时执行命令
CMD容器启动时默认命令
ENTRYPOINT容器启动入口
ENV设置环境变量
ARG构建参数
EXPOSE声明容器端口
VOLUME声明挂载点
USER指定运行用户
10.2 Dockerfile 示例:Nginx 静态站点
FROM nginx:1.25-alpine COPY ./dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]

构建和运行:

docker build -t my-nginx-site:1.0 . docker run -d --name site -p 8080:80 my-nginx-site:1.0
10.3 Dockerfile 示例:Java 应用
FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY target/app.jar /app/app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app/app.jar"]
10.4 CMD 与 ENTRYPOINT 区别

CMD提供默认启动命令,容易被docker run后面的命令覆盖。

ENTRYPOINT定义容器固定入口,更适合作为主程序入口。

示例:

ENTRYPOINT ["java", "-jar", "/app/app.jar"] CMD ["--spring.profiles.active=prod"]

运行时可以覆盖CMD参数:

docker run myapp:1.0 --spring.profiles.active=test
10.5 镜像构建优化
  1. 选择更小的基础镜像,例如 alpine、slim。
  2. 合并相关RUN指令,减少镜像层数。
  3. 使用.dockerignore排除无关文件。
  4. 利用构建缓存,把不常变化的步骤放前面。
  5. 使用多阶段构建减少最终镜像体积。
  6. 不把密码、密钥写入镜像。
  7. 尽量使用非 root 用户运行应用。
10.6 多阶段构建示例
FROM maven:3.9-eclipse-temurin-17 AS builder WORKDIR /build COPY pom.xml . COPY src ./src RUN mvn clean package -DskipTests FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY --from=builder /build/target/app.jar /app/app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app/app.jar"]

11. Docker Compose

Docker Compose 用于定义和运行多个容器。适合本地开发、测试环境和小规模部署。

11.1 Compose 常用命令
# 启动服务 docker compose up -d # 查看服务 docker compose ps # 查看日志 docker compose logs -f # 停止并删除服务 docker compose down # 重新构建镜像并启动 docker compose up -d --build # 停止服务但不删除容器 docker compose stop # 启动已停止服务 docker compose start

11.2 Compose 示例:Web + MySQL + Redis

services: app: build: . container_name: demo-app ports: - "8080:8080" environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/demo?useSSL=false&serverTimezone=Asia/Shanghai SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: 123456 SPRING_REDIS_HOST: redis depends_on: - mysql - redis networks: - app-net mysql: image: mysql:8.0 container_name: demo-mysql ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: demo volumes: - mysql-data:/var/lib/mysql networks: - app-net redis: image: redis:7 container_name: demo-redis ports: - "6379:6379" networks: - app-net networks: app-net: volumes: mysql-data:

启动:

docker compose up -d

12. Docker 日志与排错

12.1 常见排错命令
# 查看容器状态 docker ps -a # 查看容器日志 docker logs 容器名 # 查看容器详细信息 docker inspect 容器名 # 进入容器检查 docker exec -it 容器名 sh # 查看容器资源占用 docker stats # 查看端口映射 docker port 容器名 # 查看 Docker 服务日志 journalctl -u docker -f
12.2 容器启动失败排查思路
  1. docker ps -a查看容器是否退出。
  2. docker logs查看应用错误日志。
  3. 检查端口是否被占用。
  4. 检查环境变量是否配置正确。
  5. 检查挂载路径是否存在、权限是否正确。
  6. 检查镜像架构是否与服务器架构匹配。
  7. 检查容器启动命令是否正确。
12.3 端口访问不了排查思路
  1. 容器是否正在运行。
  2. 是否配置了-p 宿主机端口:容器端口
  3. 应用是否监听0.0.0.0,而不是只监听127.0.0.1
  4. 宿主机防火墙或安全组是否放行。
  5. 容器内部服务是否正常。

13. Docker 安全建议

  1. 不在镜像中写入密码、Token、私钥。
  2. 尽量不要使用--privileged
  3. 生产环境尽量使用固定版本标签,不使用latest
  4. 使用非 root 用户运行应用。
  5. 只暴露必要端口。
  6. 定期更新基础镜像。
  7. 对镜像进行漏洞扫描。
  8. 限制容器 CPU 和内存资源。
  9. 对重要数据使用 volume 持久化,并定期备份。

14. Docker 实践项目

项目 1:使用 Docker 部署 Nginx 静态网站

目标:

  1. 使用 Nginx 容器运行一个静态页面。
  2. 将宿主机目录挂载到容器。
  3. 通过浏览器访问页面。

步骤:

mkdir -p /opt/docker-demo/html echo "Hello Docker" > /opt/docker-demo/html/index.html docker run -d \ --name nginx-demo \ -p 8080:80 \ -v /opt/docker-demo/html:/usr/share/nginx/html \ nginx:1.25

访问:

http://服务器IP:8080
项目 2:使用 Docker 部署 MySQL

目标:

  1. 启动 MySQL 8 容器。
  2. 使用 volume 持久化数据。
  3. 使用客户端连接数据库。

步骤:

docker volume create mysql-data docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -e MYSQL_DATABASE=demo \ -v mysql-data:/var/lib/mysql \ --restart=always \ mysql:8.0

进入 MySQL:

docker exec -it mysql8 mysql -uroot -p123456
项目 3:使用 Dockerfile 打包 Spring Boot 项目

目标:

  1. 将 Spring Boot 项目打包成 jar。
  2. 编写 Dockerfile。
  3. 构建镜像并运行容器。

Dockerfile:

FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]

构建运行:

mvn clean package -DskipTests docker build -t springboot-demo:1.0 . docker run -d \ --name springboot-demo \ -p 8080:8080 \ springboot-demo:1.0
项目 4:使用 Docker Compose 部署完整后端环境

目标:

  1. 使用 Compose 同时启动应用、MySQL、Redis。
  2. 应用通过服务名访问 MySQL 和 Redis。
  3. 使用 volume 保存 MySQL 数据。

文件:docker-compose.yml

services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: demo volumes: - mysql-data:/var/lib/mysql networks: - app-net redis: image: redis:7 networks: - app-net app: build: . ports: - "8080:8080" environment: MYSQL_HOST: mysql REDIS_HOST: redis depends_on: - mysql - redis networks: - app-net networks: app-net: volumes: mysql-data:

启动:

docker compose up -d --build

停止:

docker compose down

15. Docker 常见面试题

1. Docker 和虚拟机有什么区别?

Docker 是进程级隔离,共享宿主机内核,启动快、资源占用少;虚拟机是硬件级虚拟化,每台虚拟机都有完整操作系统,隔离性更强但资源占用更大。

2. Docker 镜像和容器有什么区别?

镜像是只读模板,容器是镜像运行后的实例。一个镜像可以创建多个容器,容器有自己的可写层。

3. Docker 为什么启动快?

容器不需要启动完整操作系统,而是共享宿主机内核,本质上是启动一个隔离的进程,所以启动速度很快。

4. Docker 底层隔离原理是什么?

主要依赖 Linux Namespace 和 Cgroups。Namespace 负责隔离进程、网络、文件系统等资源;Cgroups 负责限制和统计 CPU、内存、I/O 等资源。

5. Docker 镜像为什么是分层的?

镜像分层可以复用已有层,减少存储空间和网络传输成本。构建镜像时,如果某一层没有变化,可以直接使用 缓存 。

6. Dockerfile 中 CMD 和 ENTRYPOINT 有什么区别?

CMD是默认命令,容易被docker run后面的参数覆盖;ENTRYPOINT是容器启动入口,通常用于固定启动主程序。二者可以配合使用,ENTRYPOINT定义程序,CMD提供默认参数。

7. COPY 和 ADD 有什么区别?

COPY只负责复制文件或目录,语义更清晰,推荐优先使用。ADD除了复制,还支持自动解压 tar 文件和从 URL 添加文件。

8. volume 和 bind mount 有什么区别?

volume 由 Docker 管理,适合数据库等持久化数据;bind mount 使用宿主机指定路径,适合挂载配置文件或代码目录。

9. 容器之间如何通信?

推荐创建自定义 bridge 网络,然后让容器加入同一个网络。这样容器之间可以通过容器名或服务名访问。

10. Docker Compose 是什么?

Docker Compose 是用于定义和管理多容器应用的工具,通过docker-compose.yml描述服务、网络、数据卷等配置,再用一条命令启动整个应用。

11. 如何减少 Docker 镜像体积?

可以选择更小的基础镜像,使用多阶段构建,合并RUN指令,清理安装缓存,使用.dockerignore排除无关文件,并避免把源码、测试文件、构建工具放入最终镜像。

12. 容器退出后数据会不会丢失?

如果数据只保存在容器可写层,删除容器后会丢失。需要持久化的数据应保存到 volume 或 bind mount 中。

13. 如何查看容器日志?
docker logs 容器名 docker logs -f 容器名 docker logs --tail 100 容器名
14. 如何进入正在运行的容器?
docker exec -it 容器名 bash

如果没有 bash:

docker exec -it 容器名 sh
15. Docker 容器访问不了外部端口怎么办?

排查方向:

  1. 容器是否运行。
  2. 是否正确配置-p端口映射。
  3. 应用是否监听0.0.0.0
  4. 防火墙或云服务器安全组是否放行。
  5. 容器日志是否报错。
16. Docker 中latest标签有什么问题?

latest不代表最新稳定版本,只是一个普通标签。生产环境使用latest可能导致版本不可控,建议使用明确版本号。

17. 什么是 Dockerfile 构建缓存?

Docker 构建镜像时会按指令逐层执行。如果某一层指令和上下文没有变化,Docker 会复用之前的缓存,从而加快构建速度。

18. 如何限制容器资源?
docker run -d \ --name app \ --memory=512m \ --cpus=1 \ nginx
19. 容器内应用为什么要前台运行?

容器的生命周期由主进程决定。如果主进程退出,容器也会退出。因此容器中的主应用一般要以前台方式运行。

20. Docker 适合运行有状态服务吗?

可以运行,但要正确处理数据持久化、备份、恢复、网络和资源限制。数据库这类有状态服务在生产环境中要更加谨慎,通常需要结合专业运维方案。

16. 学习路线建议

  1. 先掌握镜像、容器、仓库三个核心概念。
  2. 熟练使用docker rundocker psdocker logsdocker exec
  3. 学会网络和数据卷,理解容器间通信和数据持久化。
  4. 学会编写 Dockerfile,把自己的应用打包成镜像。
  5. 学会 Docker Compose,能启动一套完整开发环境。
  6. 最后再学习 Kubernetes、CI/CD、镜像仓库和生产环境部署。
http://www.gsyq.cn/news/1625644.html

相关文章:

  • std::move用法
  • Python 虚拟环境终极指南:16 款工具分类盘点,一文终结你的选择困难症
  • 如何5步构建企业级CMDB系统:open-cmdb终极指南
  • SQL注入WAF绕过实战:从混淆变形到协议攻击的攻防解析
  • Notebook到生产环境的机器学习工程化交付实战
  • KingFlow 接入 Claude Code 的 Windows / macOS / Linux 配置教程
  • VoiceFixer终极指南:三分钟让模糊语音变清晰的AI音频修复神器
  • 终极微信智能助手:5分钟搭建多AI服务自动回复机器人
  • 免费解锁9大网盘下载限制:LinkSwift直链下载助手完全指南
  • 高效多任务处理:谷歌画中画Chrome扩展插件深度解析
  • MacOS(M1)安装Claude Code
  • Test article - delete me
  • AI大模型与阿卡西记录
  • 计算机毕业设计之基于JAVA的宠物商城
  • PrismLauncher-Cracked完整指南:轻松解锁Minecraft离线账户功能
  • 【大模型】如何写一个简单的agent
  • 中国与阿塞拜疆敲定多项海关检疫合作协定
  • Anybus品牌介绍
  • AI Agent开发指南:从概念到实战
  • Python毕设选题推荐:基于 Python 的图书馆智能荐书服务管理系统的设计与实现 基于 Python 的大数据图书个性化推荐分析系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • PCL2启动器架构深度解析:模块化设计与多认证系统实现机制
  • Ethercat设备数据 转 EthernetIP项目案例
  • Deal Desk智能体实战:用LangChain+RAG构建可信B2B交易决策系统
  • 深圳本地的RFID固定资产管理系统厂商推荐
  • 测试20万qps的web接口(一)
  • 晚期胃癌新药来了,先别急着做决定——你需要知道的全在这里
  • twitter运营如何通过矩阵运营实现稳定涨粉和精准引流
  • 硬核盯盘!TradingView 移动端底层功能拆解:云端架构同步与高并发警报避坑指南
  • 人生负能量的具象化的庖丁解牛
  • C3-Ros2从零开始学习——部署Vscode+测试C++和python