Docker 容器化技术基础与实践指南
环境部署与初始化配置
在基于 RHEL/CentOS 系列的 Linux 发行版上部署 Docker 引擎,建议优先配置国内镜像源以提升下载速度。以下为标准化部署流程:
# 安装系统级依赖组件
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 注册第三方仓库配置
sudo yum-config-manager --add-repo https://repo.huaweicloud.com/docker-ce/linux/centos/docker-ce.repo
# 替换官方下载链路为国内加速节点
sudo sed -i 's+download.docker.com+repo.huaweicloud.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# 同步元数据并执行核心引擎安装
sudo yum makecache fast
sudo yum install -y docker-ce
# 启用守护进程自启服务并立即激活
sudo systemctl enable --now docker
核心管理指令速查
守护进程生命周期控制
- 激活服务:
systemctl start docker - 挂起服务:
systemctl stop docker - 重载配置:
systemctl restart docker - 健康诊断:
systemctl status docker - 开机自启:
systemctl enable docker
镜像仓库交互操作
- 本地镜像清单:
docker images或仅输出哈希值docker images -q - 远程仓库检索:
docker search <镜像关键字> - 拉取资源:
docker pull <仓库名:标签>(省略标签默认拉取latest) - 清理本地镜像:
docker rmi <镜像ID>;批量清理:docker rmi $(docker images -q)
容器实例管控
- 运行态查询:
docker ps;全量查询:docker ps -a - 实例销毁:
docker rm <容器名/ID>(需先停止或添加-f强制终止) - 元数据审查:
docker inspect <容器名/ID>
启动参数核心说明:
docker run [选项] <镜像> [命令]
-i : 保持标准输入流开放
-t : 分配伪终端设备(常与 -i 组合为 -it)
-d : 分离模式运行(后台守护)
--name : 自定义容器标识符
-p : 绑定宿主机与容器的端口映射(格式:宿主机端口:容器端口)
-P : 自动映射所有 EXPOSE 端口至宿主机随机高位端口
--rm : 容器退出时自动清理文件系统层
--restart: 故障恢复策略(always/on-failure/除非无异常)
--volume/-v : 绑定挂载宿主机目录至容器内部路径
会话交互与生命周期切换
# 注入交互式终端(不中断主进程)
docker exec -it <容器名> /bin/sh
# 暂停与恢复实例
docker stop <容器名>
docker start <容器名>
存储卷与网络架构
数据卷(Bind Mount & Volume)
数据卷是宿主机文件系统在容器内部的延伸。通过绑定挂载,宿主机与容器可实现文件级实时双向同步。该机制主要用于状态持久化、跨容器数据共享以及外部工具链接入。
典型挂载示例:
docker run -d --name web-proxy \
-p 8080:80 \
-v /srv/infra/config/nginx.conf:/etc/nginx/nginx.conf \
-v /srv/infra/static:/usr/share/nginx/html \
-v /srv/infra/logs:/var/log/nginx \
nginx:alpine
注意事项:挂载路径必须使用绝对路径;宿主机目录不存在时引擎会自动创建;支持多重 `-v` 参数叠加。
容器网络模型
Docker 通过 Linux 内核的 Namespace 和 Cgroup 实现网络隔离。核心网络驱动包括:
- bridge:默认虚拟网桥,容器间通过 NAT 互通,适合单机多服务通信。
- host:容器共享宿主机网络栈,性能最优但失去隔离性。
- none:完全禁用网络,适用于纯计算或离线数据处理任务。
- 自定义 Bridge:支持 DNS 解析、自定义子网掩码及网关配置,便于微服务分组管理。
自定义网络可通过 docker network create --driver bridge --subnet=172.20.0.0/16 my-net 创建,并在启动时通过 --network my-net 接入。
镜像构建原理与 Dockerfile
分层文件系统机制
Docker 镜像基于 UnionFS 实现多层叠加。底层通常复用宿主机的引导文件系统(bootfs),上层为只读的基础镜像层(rootfs),最终运行时会动态注入一层可读写的工作层。这种架构解释了为何不同应用镜像体积差异显著:基础层可被全局复用,实际大小取决于业务代码、依赖库及编译产物的叠加。
Dockerfile 指令集规范
Dockerfile 是声明式构建脚本,每行指令对应镜像的一层。以下为标准化模板:
# 基础运行环境定义
FROM alpine:3.18
# 维护者及版本元数据
LABEL maintainer="devops@example.com" version="2.1.0" description="Production-ready service image"
# 环境变量注入
ENV APP_HOME=/opt/app \
RUN_MODE=production \
PORT=8080
# 编译依赖安装与清理缓存
RUN apk add --no-cache curl ca-certificates && \
rm -rf /var/cache/apk/*
# 工作目录切换
WORKDIR $APP_HOME
# 文件注入与权限调整
COPY ./dist/release.tar.gz .
RUN tar -xzf release.tar.gz && rm release.tar.gz && \
chmod +x ./bin/service-daemon
# 暴露服务端口
EXPOSE $PORT/tcp
# 启动指令(推荐使用 exec 形式避免信号传递问题)
ENTRYPOINT ["./bin/service-daemon", "--config", "/opt/app/config.yml"]
CMD ["--log-level", "info"]
CMD 与 ENTRYPOINT 差异:ENTRYPOINT 定义主进程不可被 docker run 后的参数覆盖;CMD 提供默认参数,可被运行时参数替换。若两者共存,CMD 内容将作为 ENTRYPOINT 的默认参数追加。
实战案例:Java 应用容器化部署
场景一:独立 JAR 部署(Spring Boot)
提供基础 REST 接口:
package com.techdemo.restapi;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingEndpoint {
@GetMapping("/greet")
public String fetchGreeting() {
return "Welcome to containerized Spring Boot!";
}
}
Dockerfile 配置:
FROM eclipse-temurin:17-jre-alpine
WORKDIR /opt/service
# 注入编译产物
COPY target/*.jar /opt/service/app-service.jar
# 定义运行时配置
ENV JAVA_MEM_OPTS="-Xms128m -Xmx256m -Dfile.encoding=UTF-8"
ENV ACTIVE_PROFILE="prod"
# 开放应用端口
EXPOSE 9090
# 启动入口
ENTRYPOINT ["sh", "-c", "java $JAVA_MEM_OPTS -jar app-service.jar --spring.profiles.active=$ACTIVE_PROFILE"]
构建与运行:
docker build -t java-api:v2.1 .
docker run -d --rm -p 9999:9090 --name api-instance java-api:v2.1
# 测试访问: curl http://localhost:9999/greet
场景二:WAR 包部署至外部 Tomcat
适配 Spring Boot 3.x 与 Tomcat 10+ 的标准化改造:
Maven 依赖调整:
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
初始化类重写:
package com.techdemo.core;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class WebInitializer extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(WebInitializer.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(WebInitializer.class);
}
}
Dockerfile 配置:
FROM tomcat:10.1-jdk17
WORKDIR /usr/local/tomcat/webapps
# 部署归档包至 ROOT 上下文(去除路径前缀访问)
COPY *.war ROOT.war
# 启动 Tomcat 服务
ENTRYPOINT ["catalina.sh", "run"]
构建与运行:
docker build -t java-web:v1.0 .
docker run -d --rm -P java-web:v1.0