跳转到内容

Docker 容器相关操作

Docker 容器是 Docker 技术的核心概念之一,它是一个轻量级、可移植、自包含的运行环境。本文将详细介绍 Docker 容器的各种操作,帮助你更好地管理和使用容器。

Docker Container Operations

查看 docker run 命令 ,创建并且启动容器

docker run 是最常用的 Docker 命令之一,用于创建并启动一个新的容器。让我们深入了解这个命令的各个参数和用法。

bash
docker run --help

docker run 常用参数详解

bash
docker run 后面的参数
	-i # 交互式模式(interactive),保持标准输入打开,即使没有连接
	-t # 分配一个伪终端(tty),通常与 -i 一起使用形成 -it
	-v # 目录映射/挂载(volume),将宿主机的目录或文件挂载到容器中
	-d # 守护进程模式(detached),后台运行容器,返回容器ID
	-p # 端口映射(publish),格式为 宿主机端口:容器端口
	--name # 为容器指定一个名称,方便后续管理
	--rm # 容器退出后自动删除,适用于临时任务
	-e # 设置环境变量,如 -e MYSQL_ROOT_PASSWORD=123456
	--network # 指定网络模式,如 bridge、host、none 或自定义网络
	--restart # 设置重启策略,如 no、on-failure、always、unless-stopped

端口映射深入理解

端口映射是实现容器内外通信的关键。例如容器里面有 Tomcat,你本地的 Windows 想访问:

bash
# docker tomcat 端口号是8080,需要在虚拟机映射一个端口9099
# windows才可以访问 http://虚拟机ip:9099
docker run -d -p 9099:8080 tomcat

端口映射的几种形式:

  • -p 8080:80 - 映射指定端口
  • -p 8080:80/tcp - 映射 TCP 端口
  • -p 127.0.0.1:8080:80 - 绑定到特定 IP
  • -p 8080-8090:80-90 - 映射端口范围
  • -P - 随机映射所有暴露的端口

创建容器,并且进入命令行

这是最常用的交互式容器启动方式,适合调试和学习:

bash
docker run -it --name=myTomcat2 tomcat /bin/bash

参数说明:

  • -it:组合参数,-i 保持交互,-t 分配终端
  • --name=myTomcat2:为容器命名,便于识别和管理
  • tomcat:使用的镜像名称
  • /bin/bash:容器启动后执行的命令,这里是启动 bash shell

退出容器

有两种退出方式,效果不同:

bash
# 方式1:正常退出(会停止容器)
exit

# 方式2:使用快捷键(也会停止容器)
Ctrl + D

注意: 使用 exitCtrl+D 退出后,容器会停止运行。如果需要保持容器运行,请使用下面介绍的方法。

退出之后,重新进入容器

如果容器已经停止,需要先启动它;如果容器正在运行,可以直接进入。

方法一:启动已停止的容器并进入

bash
# 首先启动已停止的容器
docker start myTomcat2

# 然后进入容器
docker exec -it myTomcat2 /bin/bash

方法二:创建守护式容器(推荐)

bash
# 创建一个后台运行的守护容器
docker run -id --name=myTomcat2 tomcat

# 随时进入正在运行的容器
docker exec -it myTomcat2 /bin/bash

docker exec 的优势:

  • 不会停止容器
  • 可以在运行中的容器内执行任意命令
  • 可以多次进入同一个容器
  • 适合生产环境使用

其他进入容器的方式

bash
# 使用 sh 而不是 bash(某些精简镜像可能没有 bash)
docker exec -it myTomcat2 /bin/sh

# 以 root 用户身份进入
docker exec -it -u root myTomcat2 /bin/bash

# 在容器中执行单条命令而不进入交互模式
docker exec myTomcat2 ls -la /usr/local/tomcat

宿主机与 docker 容器的文件传递

在实际使用中,经常需要在宿主机和容器之间传输文件。Docker 提供了多种方式实现这一需求。

使用 docker cp 命令

docker cp 是最直接的文件复制方式,类似于 Linux 的 cp 命令。

从宿主机复制到容器

bash
# 1、在宿主机上创建一个文件
touch test.txt
echo "Hello Docker" > test.txt

# 2、把文件复制到容器里面去
docker cp test.txt myTomcat2:/tmp/

# 3、进入容器验证
docker exec -it myTomcat2 /bin/bash
cd /tmp
ls -la test.txt
cat test.txt

从容器复制到宿主机

bash
# 在容器中创建文件
docker exec -it myTomcat2 /bin/bash
touch /tmp/abc.txt
echo "From Container" > /tmp/abc.txt
exit

# 将容器中的文件复制到宿主机
docker cp myTomcat2:/tmp/abc.txt /root/

# 验证文件
cat /root/abc.txt

docker cp 的特点:

  • 支持文件和目录的复制
  • 不需要容器正在运行(但需要存在)
  • 复制是单向的,不会自动同步
  • 适合一次性文件传输

使用数据卷挂载(推荐用于持久化)

相比 docker cp,数据卷挂载是更优雅的解决方案,特别适合需要持续同步的场景。

bash
# 创建本地目录
mkdir -p /opt/docker-data/webapps

# 启动容器时挂载数据卷
docker run -d \
  --name=myTomcat3 \
  -p 8080:8080 \
  -v /opt/docker-data/webapps:/usr/local/tomcat/webapps \
  tomcat

# 现在在宿主机的 /opt/docker-data/webapps 放置 war 包
# 容器会自动同步,无需手动复制
cp myapp.war /opt/docker-data/webapps/

数据卷挂载的优势:

  • 实时同步,无需手动复制
  • 数据持久化,容器删除后数据不丢失
  • 性能更好,特别是大量小文件
  • 支持多个容器共享同一数据卷

其他文件传输方式

bash
# 使用 tar 进行批量传输
docker exec myTomcat2 tar czf - /path/in/container | tar xzf - -C /local/path

# 使用 docker save/load 传输整个镜像
docker save myimage > myimage.tar
docker load < myimage.tar

访问 Tomcat

在生产环境中,我们通常需要让外部能够访问容器中运行的应用。这就涉及到端口映射和数据卷的综合使用。

基本访问配置

bash
# 启动并作为守护进程
# -p 宿主机的端口: 容器里应用的端口8080
# war 挂载宿主机 -v 宿主机的路径: 容器路径
docker run -di \
  --name=myTomcat \
  -p 9999:8080 \
  -v /usr/local/tomcat/webapps:/usr/local/tomcat/webapps \
  tomcat

访问地址:http://虚拟机ip:9999

完整的 Tomcat 部署流程

bash
# 1. 准备 WAR 包
mkdir -p /opt/tomcat-webapps
cp your-application.war /opt/tomcat-webapps/

# 2. 启动 Tomcat 容器
docker run -d \
  --name=production-tomcat \
  -p 8080:8080 \
  -v /opt/tomcat-webapps:/usr/local/tomcat/webapps \
  -v /opt/tomcat-logs:/usr/local/tomcat/logs \
  -e JAVA_OPTS="-Xms512m -Xmx1024m" \
  --restart=always \
  tomcat:latest

# 3. 把war包放到宿主机的挂载目录中,直接刷新浏览器就出现项目的页面
# 访问 http://服务器IP:8080/your-application

微服务与容器化部署

在现代微服务架构中,容器化部署已成为标准实践:

bash
# 微服务 k8s 容器式的性能测试
# 单个微服务容器
docker run -d \
  --name=user-service \
  -p 8081:8080 \
  -e SPRING_PROFILES_ACTIVE=prod \
  user-service:latest

# 另一个微服务
docker run -d \
  --name=order-service \
  -p 8082:8080 \
  --link user-service \
  order-service:latest

容器化微服务的优势:

  • 环境一致性:开发、测试、生产环境完全一致
  • 快速部署:秒级启动新实例
  • 资源隔离:每个服务独立运行
  • 弹性伸缩:根据负载动态调整实例数量

容器之间的关联

在实际应用中,多个容器之间经常需要通信。Docker 提供了多种方式实现容器互联。

bash
# 先启动 MySQL 容器
docker run -d \
  --name=mysql \
  -e MYSQL_ROOT_PASSWORD=123456 \
  mysql:5.7

# 启动 Tomcat 并链接到 MySQL
docker run -di \
  --name=tomcat2 \
  -p 8080:8080 \
  --link mysql:mysql \
  tomcat

--link 的工作原理:

  • 在 tomcat2 容器的 /etc/hosts 中添加 mysql 的 IP 映射
  • 自动注入环境变量,如 MYSQL_PORT_3306_TCP_ADDR
  • 注意: 这种方式已被官方标记为遗留特性

使用自定义网络(推荐方式)

现代 Docker 推荐使用自定义网络来实现容器通信:

bash
# 1. 创建自定义网络
docker network create my-network

# 2. 启动 MySQL 容器并加入网络
docker run -d \
  --name=mysql \
  --network=my-network \
  -e MYSQL_ROOT_PASSWORD=123456 \
  mysql:5.7

# 3. 启动 Tomcat 容器并加入同一网络
docker run -d \
  --name=tomcat \
  --network=my-network \
  -p 8080:8080 \
  tomcat

# 4. 在 Tomcat 容器中可以直接通过容器名访问 MySQL
docker exec -it tomcat ping mysql

自定义网络的优势:

  • 支持 DNS 解析,直接使用容器名通信
  • 更好的网络隔离
  • 支持动态添加/移除容器
  • 可以配置网络策略

容器通信实战示例

bash
# 典型的三层架构部署
# 1. 创建网络
docker network create app-network

# 2. 启动数据库层
docker run -d \
  --name=mysql \
  --network=app-network \
  -v mysql-data:/var/lib/mysql \
  -e MYSQL_DATABASE=myapp \
  -e MYSQL_USER=app \
  -e MYSQL_PASSWORD=secret \
  mysql:8.0

# 3. 启动应用层
docker run -d \
  --name=backend \
  --network=app-network \
  -e DB_HOST=mysql \
  -e DB_PORT=3306 \
  backend-app:latest

# 4. 启动 Web 层
docker run -d \
  --name=nginx \
  --network=app-network \
  -p 80:80 \
  -v ./nginx.conf:/etc/nginx/nginx.conf \
  nginx:latest

容器生命周期管理

了解容器的完整生命周期对于有效管理至关重要。

容器状态

bash
# 查看所有容器(包括停止的)
docker ps -a

# 查看正在运行的容器
docker ps

# 查看容器详细信息
docker inspect myTomcat2

# 查看容器日志
docker logs myTomcat2
docker logs -f myTomcat2  # 实时跟踪日志
docker logs --tail 100 myTomcat2  # 查看最后100行

容器启停控制

bash
# 启动已停止的容器
docker start myTomcat2

# 停止运行中的容器
docker stop myTomcat2

# 重启容器
docker restart myTomcat2

# 强制停止容器(不推荐,除非必要)
docker kill myTomcat2

# 暂停容器(保留内存状态)
docker pause myTomcat2

# 恢复暂停的容器
docker unpause myTomcat2

容器清理

bash
# 删除已停止的容器
docker rm myTomcat2

# 强制删除运行中的容器
docker rm -f myTomcat2

# 删除所有已停止的容器
docker container prune

# 删除容器及其数据卷
docker rm -v myTomcat2

实用技巧和最佳实践

1. 容器资源限制

bash
# 限制容器使用的 CPU 和内存
docker run -d \
  --name=limited-container \
  --cpus="1.5" \
  --memory="512m" \
  --memory-swap="1g" \
  tomcat

2. 健康检查

bash
docker run -d \
  --name=healthy-tomcat \
  --health-cmd="curl -f http://localhost:8080/ || exit 1" \
  --health-interval=30s \
  --health-timeout=10s \
  --health-retries=3 \
  tomcat

# 查看健康状态
docker inspect --format='{{.State.Health.Status}}' healthy-tomcat

3. 容器备份和恢复

bash
# 基于容器创建新镜像(相当于快照)
docker commit myTomcat2 my-tomcat-backup:latest

# 导出容器文件系统
docker export myTomcat2 > container-backup.tar

# 导入为镜像
docker import container-backup.tar my-tomcat-restored:latest

4. 查看容器资源使用

bash
# 实时监控容器资源
docker stats

# 查看特定容器
docker stats myTomcat2

# 一次性输出(不持续监控)
docker stats --no-stream

常见问题排查

问题1:容器启动后立即退出

bash
# 查看容器日志
docker logs myContainer

# 常见原因:
# 1. 前台进程结束
# 2. 配置文件错误
# 3. 端口冲突
# 4. 依赖服务未就绪

问题2:无法进入容器

bash
# 检查容器是否在运行
docker ps | grep myContainer

# 尝试不同的 shell
docker exec -it myContainer /bin/sh
docker exec -it myContainer /bin/bash

# 检查容器健康状态
docker inspect myContainer | grep -A 10 Health

问题3:端口映射不生效

bash
# 检查端口占用
netstat -tlnp | grep 8080

# 检查防火墙规则
iptables -L -n

# 验证容器内部服务是否启动
docker exec myContainer netstat -tlnp

总结

本文详细介绍了 Docker 容器的各项操作,包括:

  1. 容器创建和启动:掌握 docker run 的各种参数和用法
  2. 容器交互:学会进入和退出容器,以及如何在后台运行容器
  3. 文件传输:了解 docker cp 和数据卷挂载两种方式
  4. 端口映射:实现外部访问容器内服务
  5. 容器互联:使用 --link 和自定义网络实现容器间通信
  6. 生命周期管理:掌握容器的启停、删除等操作
  7. 最佳实践:资源限制、健康检查、备份恢复等

掌握这些技能后,你将能够高效地管理和运维 Docker 容器,为后续的 Docker Compose 和 Kubernetes 学习打下坚实基础。

下一步学习建议: