docker学习笔记

Docker 学习笔记

1. Docker 是什么

Docker 是一个开源的容器化平台,用来把应用程序及其运行依赖打包成镜像,并通过容器的方式运行。容器可以理解为一个轻量级、可移植、隔离的应用运行环境。

与传统虚拟机相比,Docker 容器不需要为每个应用启动完整操作系统,而是共享宿主机内核,因此启动更快、资源占用更少、部署更方便。

常见使用场景:

  1. 开发环境统一:避免"我电脑能跑,你电脑不能跑"。
  2. 应用快速部署:镜像构建一次,可以在多台机器运行。
  3. 微服务部署:每个服务独立容器化。
  4. CI/CD 自动化发布:构建、测试、发布流程标准化。
  5. 本地快速启动中间件:MySQL、Redis、Nginx、RabbitMQ 等。

2. Docker 与虚拟机对比

对比项 Docker 容器 虚拟机
隔离方式 进程级隔离,共享宿主机内核 硬件级虚拟化,独立操作系统
启动速度 秒级甚至毫秒级 通常较慢
资源占用 较少 较多
镜像体积 通常较小 通常较大
可移植性 很强 较强
隔离强度 弱于虚拟机 更强

一句话记忆:虚拟机像"装了一台新电脑",容器像"启动了一个隔离的应用进程"。

3. 容器相关技术体系

3.1 容器核心技术

Docker 的底层依赖 Linux 内核提供的能力:

  1. Namespace:命名空间,用于资源隔离。
    • PID Namespace:进程隔离。
    • NET Namespace:网络隔离。
    • MNT Namespace:文件系统挂载隔离。
    • IPC Namespace:进程间通信隔离。
    • UTS Namespace:主机名和域名隔离。
    • USER Namespace:用户和用户组隔离。
  2. Cgroups:控制组,用于资源限制。
    • 限制 CPU 使用。
    • 限制内存使用。
    • 限制磁盘 I/O。
    • 限制进程数量。
  3. UnionFS:联合文件系统,用于镜像分层。
    • Docker 镜像由多层只读层组成。
    • 容器启动后会在镜像层之上增加一层可写层。
    • 多个镜像可以复用相同层,节省空间。

3.2 容器平台技术

容器平台通常包括:

  1. 镜像构建:Dockerfile、BuildKit。
  2. 镜像仓库:Docker Hub、Harbor、阿里云镜像仓库等。
  3. 容器运行:Docker Engine、containerd、runc。
  4. 容器编排:Docker Compose、Kubernetes。
  5. 日志监控:docker logs、ELK、Prometheus、Grafana。

3.3 容器支持技术

容器运行离不开网络、存储、安全、监控等支持能力:

  1. 网络:bridge、host、none、自定义网络。
  2. 存储:volume、bind mount、tmpfs。
  3. 安全:权限控制、只读文件系统、非 root 用户运行。
  4. 监控:容器状态、CPU、内存、网络、磁盘。
  5. 编排:服务发现、滚动更新、自动扩缩容。

4. Docker 核心概念

4.1 镜像 Image

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

特点:

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

示例:

bash 复制代码
docker pull nginx:latest
docker images

4.2 容器 Container

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

特点:

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

示例:

bash 复制代码
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 私有仓库。

常用命令:

bash 复制代码
docker login
docker tag myapp:1.0 username/myapp:1.0
docker push username/myapp:1.0
docker pull username/myapp:1.0

5. Docker 安装

以下以 CentOS Stream 8 为例。

5.1 准备环境

实验环境:

  1. 容器管理工具:Docker Engine。
  2. 容器运行时:containerd、runc。
  3. 操作系统:CentOS Stream 8。

5.2 配置 Docker 软件源

bash 复制代码
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

bash 复制代码
yum install -y docker-ce docker-ce-cli containerd.io

5.4 启动 Docker

bash 复制代码
systemctl enable docker.service --now

docker --version
systemctl status docker

5.5 配置镜像加速

bash 复制代码
mkdir -p /etc/docker
vim /etc/docker/daemon.json

示例配置:

json 复制代码
{
  "registry-mirrors": [
    "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com"
  ]
}

重启 Docker:

bash 复制代码
systemctl daemon-reload
systemctl restart docker
docker info

6. Docker 常用命令

6.1 镜像命令

bash 复制代码
# 查看本地镜像
docker images

# 搜索镜像
docker search nginx

# 拉取镜像
docker pull nginx:latest

# 删除镜像
docker rmi nginx:latest

# 查看镜像详细信息
docker inspect nginx

# 查看镜像构建历史
docker history nginx

6.2 容器命令

bash 复制代码
# 创建并启动容器
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 进入容器

bash 复制代码
docker exec -it web bash

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

bash 复制代码
docker exec -it web sh

6.4 查看日志

bash 复制代码
docker logs web
docker logs -f web
docker logs --tail 100 web

6.5 文件复制

bash 复制代码
# 从宿主机复制文件到容器
docker cp ./index.html web:/usr/share/nginx/html/index.html

# 从容器复制文件到宿主机
docker cp web:/etc/nginx/nginx.conf ./nginx.conf

6.6 查看资源占用

bash 复制代码
docker stats

6.7 清理资源

bash 复制代码
# 删除停止的容器
docker container prune

# 删除无用镜像
docker image prune

# 删除无用网络
docker network prune

# 删除无用 volume
docker volume prune

# 清理所有无用资源
docker system prune

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

7. docker run 常用参数

bash 复制代码
docker run [OPTIONS] IMAGE [COMMAND]

常用参数:

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

示例:

bash 复制代码
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 常用网络命令

bash 复制代码
# 查看网络
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 容器之间通信

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

示例:

bash 复制代码
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 管理的数据卷,适合保存数据库数据。

bash 复制代码
# 创建数据卷
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 是把宿主机目录挂载到容器中,适合挂载配置文件、项目代码。

bash 复制代码
docker run -d \
  --name web \
  -p 8080:80 \
  -v /opt/nginx/html:/usr/share/nginx/html \
  nginx

9.4 volume 与 bind mount 对比

对比项 volume bind 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 静态站点

dockerfile 复制代码
FROM nginx:1.25-alpine

COPY ./dist /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

构建和运行:

bash 复制代码
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 应用

dockerfile 复制代码
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 定义容器固定入口,更适合作为主程序入口。

示例:

dockerfile 复制代码
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
CMD ["--spring.profiles.active=prod"]

运行时可以覆盖 CMD 参数:

bash 复制代码
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 多阶段构建示例

dockerfile 复制代码
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 常用命令

bash 复制代码
# 启动服务
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

yaml 复制代码
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:

启动:

bash 复制代码
docker compose up -d

12. Docker 日志与排错

12.1 常见排错命令

bash 复制代码
# 查看容器状态
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. 通过浏览器访问页面。

步骤:

bash 复制代码
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

访问:

text 复制代码
http://服务器IP:8080

项目 2:使用 Docker 部署 MySQL

目标:

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

步骤:

bash 复制代码
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:

bash 复制代码
docker exec -it mysql8 mysql -uroot -p123456

项目 3:使用 Dockerfile 打包 Spring Boot 项目

目标:

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

Dockerfile:

dockerfile 复制代码
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app
COPY target/*.jar app.jar

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

构建运行:

bash 复制代码
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

yaml 复制代码
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:

启动:

bash 复制代码
docker compose up -d --build

停止:

bash 复制代码
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. 如何查看容器日志?

bash 复制代码
docker logs 容器名
docker logs -f 容器名
docker logs --tail 100 容器名

14. 如何进入正在运行的容器?

bash 复制代码
docker exec -it 容器名 bash

如果没有 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. 如何限制容器资源?

bash 复制代码
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、镜像仓库和生产环境部署。
相关推荐
2301_780789661 小时前
多层级 CC 防护体系:前端验证与后端限流的协同配置实践
运维·服务器·前端·网络安全·智能路由器·状态模式
秋91 小时前
Windows 环境下 Redis 部署详解:从选型、安装到生产级配置与运维
运维·windows·redis
一起逃去看海吧1 小时前
Dify-01-docker安装 和 dify部署
运维·docker·容器
H Journey1 小时前
Linux查看进程命令
linux·运维·进程
月光技术杂谈1 小时前
深度解析:基于Docker跨架构构建RK3588嵌入式rootfs的原理、边界与最佳实践
docker·容器·rootfs·rk3588·openeuler·欧拉·文件系统构建
风曦Kisaki1 小时前
# Linux运维Day01:Nginx基础
linux·运维·nginx
容器魔方1 小时前
Kthena 核心原语:ModelServing CRD 如何定义分布式推理“新标准”?
大数据·分布式·云原生·容器·云计算
头发够用的程序员1 小时前
WSL2 Ubuntu 24.04 离线安装 Docker 全流程
linux·ubuntu·docker
xingfujie1 小时前
第1章:整体架构与准备工作
linux·云原生·容器·架构·kubernetes·kubelet