一文学懂Docker——从快速入门到项目部署

发布于:2025-07-08 ⋅ 阅读:(23) ⋅ 点赞:(0)

Docker学习笔记

1. Docker简介

1.1 什么是Docker

Docker是一种开源的容器化平台,用于快速构建、部署和运行应用程序。它通过容器技术将应用程序及其依赖环境打包成一个轻量级、可移植的标准化单元,确保应用在不同计算环境中一致运行。

核心优势

  • Docker容器与传统虚拟机不同,共享主机操作系统内核
  • 无需模拟完整操作系统,启动更快、占用资源更少
  • 通过Dockerfile定义容器配置,实现自动化构建和版本控制

应用场景

  • 微服务架构
  • 持续集成/交付(CI/CD)
  • 开发环境标准化
  • 利用Docker Hub丰富的预构建镜像简化开发

生态系统

  • Docker Compose(多容器编排)
  • Docker Swarm(集群管理)
  • Kubernetes(容器编排)

2. 安装Docker

我的博客下有详细的文档,就不在这里过多赘述,各位彦祖亦菲们请移步下方对应文档即可:


3. Docker基础入门

3.1 docker常见命令

官方文档:Docker Docs
以一张图为例,简述docker常见使用命令
​​​​在这里插入图片描述

3.2 Docker 常见命令对照表

命令 作用 示例
docker pull 拉取镜像到本地 docker pull nginx:alpine
拉取Nginx的Alpine版本镜像
docker push 推送镜像到仓库 docker push myrepo/myapp:v1.0
推送自定义镜像到私有仓库
docker images 查看所有本地镜像 docker images -a
显示所有镜像(包括中间层)
docker rmi 删除本地镜像 docker rmi ubuntu:18.04
删除Ubuntu 18.04镜像
docker run 创建并运行容器 docker run -d -p 8080:80 --name web nginx
后台运行Nginx容器
docker stop 停止运行中的容器 docker stop web
停止名为web的容器
docker start 启动已停止的容器 docker start web
重新启动web容器
docker exec 在运行中的容器执行命令 docker exec -it web bash
进入web容器的交互式bash终端
docker logs 查看容器日志 docker logs -f --tail 100 web
实时查看web容器最后100行日志
docker ps 查看运行中的容器 docker ps -a
显示所有容器(包括已停止的)
docker rm 删除容器 docker rm -f web
强制删除web容器(包括运行中的)
docker load 从文件加载镜像 docker load < myapp.tar
从tar文件加载镜像
docker save 将镜像保存到文件 docker save -o nginx.tar nginx:latest
保存Nginx镜像到tar文件
docker build 构建镜像 docker build -t myapp:v1 .
使用当前目录Dockerfile构建镜像

小技巧:
带-it参数:进入交互模式(如docker exec -it)
带-d参数:后台运行容器(如docker run -d)
带-p参数:端口映射(主机端口:容器端口)
带-v参数:目录挂载(主机路径:容器路径)
带–name参数:指定容器名称
组合命令示例:docker exec -it mysql mysql -uroot -p 直接进入MySQL命令行

💡 使用提示:
当不知道用法,或不知道还有什么参数可以跟的时候,可以使用–help进行查看用法,例如docker ps --help可以提示你docker ps -a可以查看所有容器,包括未运行的


3.2 数据卷挂载

3.2.1 什么是Docker数据卷

Docker数据卷(Volume)是用于持久化存储容器数据的核心机制,本质上是特殊目录,直接映射到主机文件系统。

主要特点

  • 持久化:生命周期独立于容器
  • 共享性:支持多容器同时挂载
  • 高性能:直接访问主机文件系统
  • 可移植:支持跨主机迁移备份
3.2.2 数据卷常见命令
docker volume create [卷名]      # 创建数据卷
docker volume ls               # 列出所有数据卷
docker volume inspect [卷名]   # 查看卷详情
docker volume rm [卷名]        # 删除数据卷
3.2.3 挂载数据卷

docker run时使用-v参数挂载:

# 创建命名数据卷
docker volume create html

# 启动容器时挂载数据卷
docker run -d --name nginx -v html:/usr/share/nginx/html nginx

详细拆解
docker run -d --name nginx -v html:/usr/share/nginx/html nginx

命令 说明 作用
docker run 创建一个docker容器 创建一个docker容器
-d 使容器在后台运行 使容器在后台运行
–name nginx 给容器命名 将容器命名为nginx
-v 指定挂载 用于指定挂载卷
html:/usr/share/nginx/html html指宿主机的路径;/usr/share/nginx/html 是容器中静态文件的绝对路径 挂载容器数据卷到宿主机
nginx 容器 指定docker中的容器

注意:
docker容器中的文件路径应该如何寻找可以参考详细的[docker仓库官方文档](https://hub.docker.com/) 但该网站需要科学上网哦

注意事项

  1. 容器创建后无法再指定挂载,需删除重建
  2. 挂载时数据卷不存在会自动创建

3.3 本地目录挂载

3.3.1 什么是本地目录挂载

同样也是通过-v参数将宿主机物理路径映射到容器内部:

docker run -v /宿主机/绝对路径:/容器内目录 nginx

与数据卷的区别

特性 数据卷 本地目录挂载
存储位置 Docker管理区域 宿主机指定路径
创建方式 docker volume create 直接使用现有目录
路径格式 名称(如mysqlnginx 绝对路径(如/data
3.3.2 挂载本地目录
# 正确示例(绝对路径)
docker run -v /home/user/app:/app nginx

# 正确示例(相对路径)
docker run -v ./mysql:/var/lib/mysql mysql

# 错误识别(会被当作数据卷进行挂载)
docker run -v mysql:/var/lib/mysql mysql

关键区别

  • /./开头 → 识别为本地目录
  • 直接以名称开头 → 识别为数据卷

4.练手时刻之——快速部署MySQL和Nginx

4.1 配置镜像加速器

问题:直接docker run可能因国外源导致超时
在这里插入图片描述
原因:因为docker run默认是去官方的镜像仓库拉取镜像,但官方的仓库是在国外的,因此要么会链接超时,要么会拉取的特别慢,所以在我们真正进行拉取的时候,还需要做一步:配置镜像加速器

解决方案(阿里云为例)

  1. 登录阿里云控制台 → 搜索"容器镜像服务"
  2. 获取镜像仓库加速器地址(如https://xxxx.mirror.aliyuncs.com
  3. 在宿主机执行:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

附图
在这里插入图片描述
验证配置是否生效

docker info | grep Mirrors -A 2

小提示:
若未生效以下还有个邪修流派的方法:
将以下命令全部复制,并修改vi /etc/docker/daemon.json

{
    "registry-mirrors": [
    "https://docker.1panelproxy.com",
    "https://docker.m.daocloud.io",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com",
    "https://dockerhub.icu",
    "https://docker.registry.cyou",
    "https://docker-cf.registry.cyou",
    "https://dockercf.jsdelivr.fyi",
    "https://docker.jsdelivr.fyi",
    "https://dockertest.jsdelivr.fyi",
    "https://mirror.aliyuncs.com",
    "https://dockerproxy.com",
    "https://mirror.baidubce.com",
    "https://docker.m.daocloud.io",
    "https://docker.nju.edu.cn",
    "https://docker.mirrors.sjtug.sjtu.edu.cn",
    "https://docker.mirrors.ustc.edu.cn",
    "https://mirror.iscas.ac.cn",
    "https://docker.rainbond.cc"
    ]
}

4.2 部署命令示例

# 部署MySQL(带密码和端口映射)
docker run -d --name mysql \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -p 3306:3306 \
  -v mysql_data:/var/lib/mysql \
  mysql:8.0

# 部署Nginx(带目录挂载)
docker run -d --name nginx \
  -p 80:80 \
  -v ./html:/usr/share/nginx/html \
  nginx:alpine

💡 提示:首次运行会自动拉取镜像,配置加速器后可大幅提升下载速度


5. 自定义镜像(制作镜像)

5.1 为什么要自定义镜像?

在Docker生态中,官方镜像提供了各种语言和框架的基础环境,但在实际生产环境中,我们几乎总是需要创建自定义镜像,主要原因包括:

  1. 环境标准化需求
    不同应用需要特定的运行时配置(如时区、字符集)、依赖库版本和安全策略,自定义镜像确保开发、测试、生产环境完全一致。

  2. 应用封装要求
    将应用程序与其运行环境打包成不可变单元,实现"一次构建,处处运行"的承诺,避免环境差异导致的问题。

  3. 安全加固必要
    官方基础镜像通常包含非必要的工具和权限,自定义镜像可以:
    移除不必要的软件包
    使用非root用户运行应用
    设置严格的权限控制
    集成安全扫描工具

  4. 性能优化空间
    通过精简镜像层、选择更小的基础镜像(如Alpine Linux)、优化构建过程,可显著减小镜像体积,加速部署和启动过程。

  5. 企业合规要求
    满足内部审计规范,集成公司标准的监控代理、日志收集组件和安全证书。

典型案例:当你的Java应用需要特定时区(如东八区)、自定义JVM参数和私有依赖库时,官方OpenJDK镜像就无法直接满足需求,必须通过自定义镜像实现。

5.2 Dockerfile基础语法

Dockerfile是构建镜像的蓝图,由一系列指令组成,核心语法包括:

指令 作用描述 示例
FROM 指定基础镜像(必须第一条指令) FROM openjdk:17-jdk-slim
WORKDIR 设置工作目录(后续指令的相对路径) WORKDIR /app
COPY 复制文件/目录到镜像中 COPY target/app.jar ./
ADD 高级复制(支持URL和解压) ADD https://example.com/file.tar.gz /
RUN 执行命令并创建新的镜像层 RUN apt-get update && apt-get install -y curl
ENV 设置环境变量 ENV TZ=Asia/Shanghai
ARG 构建时变量(构建结束后不可用) ARG APP_VERSION=1.0.0
EXPOSE 声明容器运行时监听的端口 EXPOSE 8080
USER 设置运行用户(提升安全性) USER 1000
ENTRYPOINT 容器启动命令(不可被覆盖) ENTRYPOINT ["java", "-jar"]
CMD 默认命令参数(可被docker run覆盖) CMD ["app.jar"]
VOLUME 创建挂载点 VOLUME ["/data"]

最佳实践原则

  1. 指令按稳定性排序(从最稳定到最易变)
  2. 合并RUN指令减少镜像层数
  3. 使用.dockerignore排除无关文件
  4. 多阶段构建分离编译环境和运行环境
  5. 明确指定镜像版本(避免使用latest标签)

5.3 自定义镜像实战

下面以构建一个Java应用镜像为例,演示完整的Dockerfile制作流程:

需求场景

  • 基于OpenJDK 17
  • 设置东八区时区
  • 通过外部挂载配置文件
  • 使用非root用户运行
  • 支持健康检查

Dockerfile实现

# 第一阶段:运行环境
FROM openjdk:17-jdk-slim

# 第二阶段:设置时区(东八区)
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone

# 第三阶段:设置工作目录
WORKDIR /data

# 创建配置目录和日志目录(按需)
RUN mkdir -p /data/config /data/logs

# 从构建阶段复制JAR文件
COPY your-application.jar /data

# 启动命令(从config目录加载配置)
ENTRYPOINT ["java", "-Dspring.config.location=file:/data/config/", "-jar", "your-application.jar"]

构建与运行

# 构建镜像
docker build -t my-java-demo:1.0.0 .

# 运行容器(挂载配置文件目录)
docker run -d \
  --name java-app \
  -p 8080:8080 \
  -v /host/config:/data/config \
  my-java-app:1.0.0

关键优化点

  1. 多阶段构建:分离构建环境和运行环境,最终镜像不包含Maven等构建工具
  2. 权限控制:创建专用用户appuser运行应用,降低安全风险
  3. 配置分离:通过VOLUME声明配置目录,运行时动态挂载
  4. 健康监控:添加HEALTHCHECK确保应用可用性
  5. 时区设置:确保应用使用正确的时区(东八区)

6. Docker容器网络解析

6.1 理解容器网络基础

6.1.1网络架构图解
宿主机
Docker网桥 docker0
容器1 172.17.0.2
容器2 172.17.0.3
容器3 172.17.0.4
物理网卡 eth0
外部网络
6.1.2核心概念解析
  1. 网桥机制

    • 在安装Docker后默认会在宿主机创建虚拟网桥docker0作为网络枢纽
    • 所有容器通过veth pair虚拟设备连接到该网桥
    • 默认IP分配范围:172.17.0.0/16
  2. 容器独立IP

    # 查看容器IP地址
    docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名
    
    • 每个容器获得独立IP(如172.17.0.2
    • 容器间通过IP直接通信
    • 宿主机可通过docker0网桥访问容器
  3. IP变动问题

    • 容器重启后IP会重新分配
    • 服务依赖固定IP时会导致连接失败

6.2 自定义网络

6.2.1Docker网络管理常用命令
命令 作用 示例
docker network ls 列出所有网络 docker network ls
docker network create 创建新网络 docker network create -d bridge backend-net
docker network inspect 查看网络详情 docker network inspect backend-net
docker network connect 连接容器到网络 docker network connect backend-net mysql
docker network disconnect 从网络断开容器 docker network disconnect backend-net redis
docker network prune 清理未使用网络 docker network prune -f
docker network rm 删除网络 docker network rm test-net
6.2.2如何创建自定义网络
# 创建自定义网络
docker network create networkname

# 创建带网关、子网的自定义网络
docker network create \
  --driver bridge \
  --subnet 192.168.100.0/24 \
  --gateway 192.168.100.1 \
  networkname
6.2.3容器加入自定义网络
# 在创建、启动容器时加入网络
docker run -d --name containername --network networkname nginx

# 将已有容器加入网络
docker network connect networkname containername

6.3 固定容器IP

方法1:自定义网络指定IP
docker run -d --name containername \
  --network networkname \
  --ip 192.168.100.1 \  # 固定容器IP地址
  nginx

注意事项

  • 必须使用自定义网络才能固定容器IP(非默认bridge)
  • 指定的IP需在子网范围内(如192.168.100.0/24
  • 每个IP在子网内必须唯一
方法2:通过容器名配置(推荐)
# 在相同网络中的容器
docker run -d --name containername --network networkname nginx

# 在容器内可通过名称访问其他容器
ping nginx # 自动解析为192.168.100.100

核心优势

  • 无需记忆IP地址
  • 容器重启后名称不变
  • 自动DNS解析(Docker内置DNS服务器)

6.4 网络规划——经典案例

6.4.1多服务服务器网络架构示意图
data-net
backend-net
frontend-net
MySQL
Redis
用户服务
订单服务
API网关
Web容器
6.4.2实施步骤示例
# 1. 创建隔离网络
docker network create frontend-net
docker network create backend-net
docker network create data-net

# 2. 启动数据库服务(仅加入数据网络)
docker run -d --name mysql-db --network data-net mysql
docker run -d --name redis-cache --network data-net redis

# 3. 启动后端服务(连接后端和数据网络)
docker run -d --name user-service --network backend-net user-service
docker network connect data-net user-service

# 4. 启动前端服务(连接前端和后端网络)
docker run -d --name api-gateway -p 80:80 --network frontend-net api-gateway
docker network connect backend-net api-gateway
6.4.3安全加固策略
  1. 网络分层隔离

    • 前端网络:暴露80/443端口
    • 后端网络:不直接暴露端口
    • 数据网络:完全隔离,仅允许后端访问
  2. 访问控制

    # 创建仅允许特定容器访问的网络
    docker network create --internal secure-net
    
    # 启动敏感服务
    docker run -d --name audit-log --network secure-net audit-service
    
  3. 端口管理

    • 使用-p 8080:80显式映射端口
    • 避免使用-P随机映射敏感服务

7.Docker项目部署实战

7.1 Java应用容器化部署

核心部署流程

应用代码
Dockerfile构建
运行容器
配置文件挂载
动态配置更新

7.1.1 Dockerfile(支持外部配置)

FROM openjdk:17-jdk-slim

# 设置默认环境变量
ENV CONFIG_DIR=/external-config

# 创建配置目录(用于挂载外部配置)
RUN mkdir -p ${CONFIG_DIR}

# 复制应用JAR(不含配置)
COPY target/myapp.jar /app/app.jar

# 设置启动命令(优先使用外部配置)
ENTRYPOINT ["sh", "-c", "java -jar /app/app.jar \
--spring.config.location=${CONFIG_DIR}/application.yml"]

7.1.2 部署与配置管理

# 1. 构建镜像
docker build -t my-java-app:2.0 .

# 2. 首次运行(挂载配置文件)
docker run -d --name java-service \
  -p 8080:8080 \
  -v yourfolder/config:/external-config \  # 挂载配置目录
  my-java-app:2.0

# 3. 修改配置后重启生效
vim config/application.yml  # 修改配置文件
docker restart java-service

7.1.3 配置文件热更新技巧

# 查看当前配置
docker exec java-service cat /external-config/application.yml

# 动态更新配置(无需重启)
curl -X POST http://localhost:8080/actuator/refresh

# 监控配置变化
docker logs -f java-service | grep "Config change"

7.2 前端应用容器化部署

7.2.1 部署架构流程

源代码
构建静态文件
Nginx容器
配置文件挂载
动态路由配置

7.2.2 Dockerfile(支持外部配置)

# 构建阶段(不变)
FROM node:16 as builder
...

# 生产阶段(支持外部配置挂载)
FROM nginx:alpine

# 复制默认静态文件
COPY --from=builder /app/build /usr/share/nginx/html

# 创建配置目录
RUN mkdir -p /etc/nginx/external-conf

# 复制默认配置(可作为模板)
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 启动脚本(优先加载外部配置)
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

7.2.3 entrypoint.sh 启动脚本

#!/bin/sh

# 检查是否存在外部配置
if [ -f "/etc/nginx/external-conf/nginx.conf" ]; then
  cp /etc/nginx/external-conf/nginx.conf /etc/nginx/conf.d/
fi

# 启动Nginx
exec nginx -g 'daemon off;'

7.2.4 部署与配置管理

# 1. 构建镜像
docker build -t my-frontend:2.0 -f Dockerfile.prod .

# 2. 运行容器(挂载配置目录)
docker run -d --name frontend \
  -p 80:80 \
  -v yourfolder/nginx-conf:/etc/nginx/external-conf \  # 挂载配置目录
  my-frontend:2.0

# 3. 修改路由配置
vim nginx-conf/nginx.conf  # 添加新的代理规则

# 4. 热重载配置(无需重启容器)
docker exec frontend nginx -s reload

7.2.5 动态配置示例

# nginx.conf (可动态修改)
server {
    location /api/v1 {
        proxy_pass http://backend-service:8080;
    }
    
    location /api/v2 {
        proxy_pass http://new-backend:8081;
    }
}

7.3 Docker Compose

7.3.1 Docker命令 vs Compose对比

功能 Docker命令 docker-compose.yml
启动服务 docker run -d --name frontend -p 80:80 frontend-image services: frontend: image: frontend-image ports: - "80:80"
网络配置 docker network create app-net
docker run --network app-net ...
networks: app-net: driver: bridge
数据卷挂载 docker run -v ./data:/app/data ... volumes: - ./data:/app/data
环境变量 docker run -e "DB_HOST=db" ... environment: - DB_HOST=db
依赖管理 需手动控制启动顺序 depends_on: - db
多容器启动 多个docker run命令 单条docker-compose up命令

7.3.2 docker-compose.yml结构

version: '3.8'

services:
  frontend:
    image: my-frontend:2.0
    ports: ["80:80"]
    volumes:
      - ./frontend/nginx-conf:/etc/nginx/external-conf  # 挂载前端配置
    networks: ["app-net"]
    depends_on: ["backend"]

  backend:
    image: my-java-app:2.0
    ports: ["8080:8080"]
    volumes:
      - ./backend/config:/external-config  # 挂载Java配置
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    networks: ["app-net"]
    depends_on: ["mysql", "redis"]

  mysql:
    image: mysql:8.0
    volumes: ["mysql-data:/var/lib/mysql"]
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}  # 使用环境变量
    networks: ["app-net"]

  redis:
    image: redis:6.2-alpine
    networks: ["app-net"]

networks:
  app-net:
    driver: bridge

volumes:
  mysql-data:

7.3.3 完整部署工作流

# 1. 构建镜像(可选)
docker-compose build

# 2. 启动所有服务
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# 3. 动态调整配置
# 修改配置文件后执行:
docker-compose restart backend  # Java应用
docker-compose exec frontend nginx -s reload  # 前端路由

# 4. 监控服务状态
docker-compose ps
docker-compose logs -f

# 5. 安全关闭
docker-compose down --volumes --remove-orphans

网站公告

今日签到

点亮在社区的每一天
去签到