服务器与Docker技术指南
服务器、Docker容器和物理地址之间的关系可以这样理解: 物理地址:指的是服务器的实际硬件位置,包含真实的CPU、内存、存储设备等物理资源。每台物理服务器都有唯一的MAC地址用于网络识别。 服务器:可以是物理机器(物理服务器),也可以是虚拟机。它提供计算资源和运行环境,有自己的操作系统、IP地址等。 Docker容器:是在服务器上运行的轻量级虚拟化环境,共享宿主服务器的内核,但拥有独立的文件系统、进程空间和网络配置。
关系: Docker容器运行在服务器之上,利用服务器的物理资源 多个容器可以在同一台服务器上并行运行,共享物理资源但彼此隔离 容器可以有自己的虚拟IP地址,通过端口映射与外部网络通信 容器内的应用不直接访问物理地址,而是通过Docker的网络层进行通信 简言之,物理地址提供实际硬件资源,服务器提供运行环境,Docker容器则在服务器上提供隔离的应用运行空间。
Docker 基础概念
Docker 架构
- Docker引擎:Docker的核心组件,包括Docker守护进程(Docker daemon)、REST API和CLI客户端
- Docker镜像:容器的只读模板,包含运行应用所需的文件系统、代码、运行时和依赖
- Docker容器:镜像的运行实例,拥有独立的文件系统、网络和进程空间
- Docker仓库:存储和分发Docker镜像的地方,如Docker Hub、私有仓库等
Docker 基本命令
# 拉取镜像
docker pull [镜像名]:[标签]
# 构建镜像
docker build -t [镜像名]:[标签] [Dockerfile目录]
# 运行容器
docker run [选项] [镜像名]
# 查看镜像列表
docker images
# 删除镜像
docker rmi [镜像ID]
# 删除容器
docker rm [容器ID]
容器生命周期管理
容器状态转换
- 创建:
docker create- 创建但不启动容器 - 启动:
docker start- 启动已创建的容器 - 运行:
docker run- 创建并启动容器 - 暂停:
docker pause- 暂停容器中的所有进程 - 恢复:
docker unpause- 恢复容器中被暂停的进程 - 停止:
docker stop- 发送SIGTERM信号,优雅停止容器 - 强制停止:
docker kill- 发送SIGKILL信号,立即停止容器 - 重启:
docker restart- 重启容器 - 删除:
docker rm- 删除已停止的容器
SSH 和 jupter SSH连接的是物理机(宿主机)- 您通过SSH协议直接连接到运行Docker的物理服务器上,获得物理机的shell访问权限。 Jupyter打开的是Docker容器的端口 - Jupyter服务运行在Docker容器内部,容器将Jupyter的端口(通常是8888)映射到物理机的某个端口上,使您可以通过浏览器访问。 Docker的文件和物理机之间有一个映射 - 这通过Docker的卷(volume)或绑定挂载(bind mount)实现,允许容器内的进程访问物理机上的文件系统。当您在Jupyter中编辑文件时,实际上是在操作这个映射的文件系统。 这种架构使您可以在隔离的容器环境中运行Jupyter,同时仍能通过SSH访问底层的物理机进行管理。
Docker 数据管理详解
卷(Volumes)与绑定挂载(Bind Mounts)的区别
- 卷(Volumes):由Docker管理,存储在Docker区域内,更安全,跨平台支持更好
- 绑定挂载(Bind Mounts):直接映射主机文件系统的路径到容器内,依赖主机文件系统
数据持久化最佳实践
# 创建命名卷
docker volume create my_volume
# 使用卷运行容器
docker run -v my_volume:/container/path image_name
# 使用绑定挂载
docker run -v /host/path:/container/path image_name
# 查看卷的详细信息
docker volume inspect my_volume
# 移除未使用的卷
docker volume prune
Docker 网络详解
网络类型
- bridge:默认网络,容器通过虚拟网桥连接
- host:容器使用主机网络栈,无网络隔离
- none:容器没有网络连接
- overlay:用于Docker Swarm服务间通信的多主机网络
- macvlan:允许容器拥有自己的MAC地址
- ipvlan:类似macvlan,但共享MAC地址
自定义网络
# 创建自定义网络
docker network create --driver bridge my_network
# 使用自定义网络运行容器
docker run --network=my_network image_name
# 将容器连接到网络
docker network connect my_network container_name
# 断开容器与网络的连接
docker network disconnect my_network container_name
Q 获得物理机的shell访问权限是什么 A 获得物理机的shell访问权限是指通过SSH协议连接到运行Docker的物理服务器上,直接获得物理机的shell环境。这通常用于管理物理机上的文件、目录、进程等。
Q shell环境是什么 A shell环境是指用户与操作系统交互的界面,它提供命令行界面,允许用户输入命令并执行。在Linux和Unix系统中,常见的shell有bash、sh、csh等。通过shell环境,用户可以执行各种系统命令、脚本程序,以及运行应用程序。
Docker 安全性
安全最佳实践
- 使用非root用户运行容器:
docker run --user 1000:1000 image_name - 限制容器资源:使用
--memory和--cpu选项 - 使用只读文件系统:
docker run --read-only image_name - 定期更新镜像以修复漏洞
- 扫描镜像中的安全漏洞:
docker scan image_name - 使用Docker Content Trust验证镜像:
export DOCKER_CONTENT_TRUST=1
特权容器和安全隐患
特权容器(--privileged)可以访问主机的所有设备,具有与主机相同的权限,应谨慎使用,仅在必要时启用。
Docker容器、SSH和物理机交互的详细操作指南 下面是详细的执行细节和查看方式,帮助您理解和操作Docker容器、SSH连接和物理机之间的关系:
# 连接到物理机
ssh username@server_ip
# 连接成功后,您会获得物理机的shell
username@server_ip:~$
# 查看Docker容器列表
docker ps
# 示例输出
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123def456 jupyter/scipy "jupyter notebook --…" 2 hours ago Up 2 hours 0.0.0.0:8888->8888/tcp jupyter_container
# 查看Docker容器详细信息
docker inspect container_id_or_name
# 查看Docker容器的网络配置
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_id_or_name
# 查看Docker容器的端口映射
docker port container_id_or_name
# 连接到Docker容器
docker exec -it container_id_or_name /bin/bash
# 示例输出
root@abc123def456:/#
# 在Docker容器中运行Jupyter Notebook
jupyter notebook --ip=0.0.0.0 --port=8888 --no-browser --allow-root
# 在物理机上访问Jupyter Notebook
http://server_ip:8888
# 在Docker容器中查看Jupyter Notebook的日志
jupyter notebook list
# 示例输出
Currently running servers:
http://0.0.0.0:8888/?token=abcdef1234567890abcdef1234567890 :: /home/jovyan/work
# 在物理机上访问Jupyter Notebook的日志
http://server_ip:8888/?token=abcdef1234567890abcdef1234567890
# 在Docker容器中停止Jupyter Notebook
jupyter notebook stop
# 在Docker容器中重启Jupyter Notebook
jupyter notebook restart
# 在Docker容器中查看Jupyter Notebook的配置文件
jupyter notebook --generate-config
# 在Docker容器中查看Jupyter Notebook的配置文件
jupyter notebook --config
# 在Docker容器中查看Jupyter Notebook的配置文件
jupyter notebook --config-dir
Docker Compose与多容器应用
Docker Compose基础
Docker Compose是用于定义和运行多容器Docker应用的工具,使用YAML文件配置应用的服务。
# docker-compose.yml示例
version: '3'
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
常用Docker Compose命令
# 启动所有服务
docker-compose up
# 在后台启动所有服务
docker-compose up -d
# 停止所有服务
docker-compose down
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs
- 查看端口映射
docker port container_id_or_name
# 查看特定容器的详细信息,包括端口映射
docker inspect -f '{{range $p, $conf := .NetworkSettings.Ports}}{{$p}} -> {{(index $conf 0).HostPort}}{{end}}' jupyter_container
# 示例输出
8888/tcp -> 8888
- 查看文件映射(卷和绑定挂载)
# 查看容器的卷映射
docker inspect -f '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}' jupyter_container
# 示例输出
/home/username/jupyter_data -> /home/jovyan/work
- 进入Docker容器内部
# 进入运行中的容器
docker exec -it jupyter_container bash
# 现在您在容器内部
jovyan@abc123def456:~$
- 在容器内外验证文件映射
# 在物理机上创建测试文件
echo "Hello from host" > /home/username/jupyter_data/test_file.txt
# 进入容器查看文件
docker exec -it jupyter_container bash -c "cat /home/jovyan/work/test_file.txt"
# 输出: Hello from host
# 从容器内部修改文件
docker exec -it jupyter_container bash -c "echo 'Hello from container' >> /home/jovyan/work/test_file.txt"
# 在物理机上查看变化
cat /home/username/jupyter_data/test_file.txt
# 输出:
# Hello from host
# Hello from container
- 访问Jupyter服务 在浏览器中访问:http://server_ip:8888 如果您是通过SSH隧道连接的:
# 在本地机器上创建SSH隧道
ssh -L 8888:localhost:8888 username@server_ip
# 然后在本地浏览器访问
http://localhost:8888
- 查看网络配置
# 查看物理机网络接口
ip addr show
# 查看Docker网络
docker network ls
# 查看特定Docker网络详情
docker network inspect bridge
# 查看容器内部网络配置
docker exec jupyter_container ip addr show
- 查看Docker容器的资源使用情况
# 查看容器资源使用情况
docker stats jupyter_container
# 查看容器日志
docker logs jupyter_container
- 检查Docker卷
# 列出所有Docker卷
docker volume ls
# 查看特定卷的详细信息
docker volume inspect volume_name
退出交互式容器会话
# 方法1:输入exit命令
exit
# 方法2:使用键盘组合键
# 按Ctrl+D
Docker资源管理与限制
限制容器资源
# 限制CPU使用
docker run --cpus=0.5 image_name # 限制使用0.5个CPU核心
# 限制内存使用
docker run --memory=1g image_name # 限制使用1GB内存
# 限制交换空间
docker run --memory-swap=2g image_name # 限制内存+交换空间总共2GB
# 设置重启策略
docker run --restart=always image_name # 总是重启容器
优雅停止容器(发送SIGTERM信号,等待容器清理后退出)
docker stop 容器ID或容器名称
示例
docker stop jupyter_container
强制立即停止容器(发送SIGKILL信号)
docker kill 容器ID或容器名称
这是docker stats命令的输出结果,显示了名为"commonService"的容器的实时资源使用情况。这个命令会持续更新容器的性能数据,所以您看到了三次几乎相同的输出。我来解释每一列的含义: CONTAINER ID: 6860a06aae63 - 容器的唯一标识符 NAME: commonService - 容器的名称 CPU %: 3.95%/3.52% - 容器使用的CPU百分比,可以看到使用率略有波动 MEM USAGE / LIMIT: 18.62GiB / 251.3GiB - 内存使用情况和限制 容器当前使用了18.62GB内存 容器被允许使用的最大内存是251.3GB MEM %: 7.41% - 内存使用占限制的百分比 NET I/O: 149GB / 38.4GB - 网络输入/输出总量 容器已接收149GB的数据 容器已发送38.4GB的数据 BLOCK I/O: 18.2GB / 236GB - 块设备(磁盘)读/写总量 容器已读取18.2GB的数据 容器已写入236GB的数据 PIDS: 373 - 容器内运行的进程数量 这些数据表明这是一个相当大型的服务容器,使用了大量内存(18.62GB),有大量的网络传输(接收149GB,发送38.4GB)和磁盘写入(236GB),并运行了多个进程(373个)。CPU使用率相对适中,在3.5%-4%左右。
Dockerfile与镜像构建最佳实践
Dockerfile基本指令
FROM node:14 # 基础镜像
WORKDIR /app # 工作目录
COPY package*.json ./ # 复制文件
RUN npm install # 运行命令
COPY . . # 复制所有文件
EXPOSE 3000 # 暴露端口
CMD ["npm", "start"] # 容器启动命令
镜像构建最佳实践
- 使用多阶段构建减小镜像大小
- 合并RUN指令减少镜像层数
- 使用.dockerignore排除不必要的文件
- 安装后清理缓存(如apt-get clean)
- 使用特定标签而非latest
- 使用非root用户运行应用
查看Docker容器的GPU显存占用 要查看Docker容器的GPU显存占用,您需要使用NVIDIA的工具,因为Docker stats命令本身不显示GPU相关信息。以下是几种查看方法:
- 使用nvidia-smi命令 如果您的容器使用了NVIDIA GPU,最直接的方法是:
# 在物理机上查看所有GPU状态和显存占用
nvidia-smi
# 查看实时更新的GPU状态(每1秒刷新)
nvidia-smi --loop=1
示例输出:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 515.65.01 Driver Version: 515.65.01 CUDA Version: 11.7 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... On | 00000000:00:1E.0 Off | 0 |
| N/A 37C P0 42W / 300W | 15360MiB / 16384MiB | 18% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
Q 这个命令里GPU怎么看 A 这个命令里GPU的编号是0,表示第一块GPU。
- 在容器内部查看GPU显存 如果容器有权限访问GPU,可以在容器内部执行:
# 在容器内部查看GPU状态
nvidia-smi
# 在容器内部查看GPU显存
nvidia-smi --query-gpu=memory.used --format=csv
示例输出:
memory.used
15360MiB
- 查看特定容器的GPU使用情况 使用NVIDIA的Docker集成工具:
# 安装nvidia-container-toolkit(如果尚未安装)
sudo apt-get install -y nvidia-container-toolkit
# 使用nvidia-docker命令查看特定容器的GPU使用
nvidia-docker stats 容器名称或ID
- 使用nvidia-smi查询特定进程 找出容器中的进程ID,然后查询该进程的GPU使用情况:
# 查找容器中的进程ID
docker top 容器名称或ID
# 查询进程的GPU使用情况
nvidia-smi --query-compute-apps=pid,used_memory --format=csv,noheader
示例输出:
PID Used GPU Memory
12345 15360MiB
- 使用Docker命令行工具查询GPU使用情况 Docker命令行工具本身不直接提供查询GPU使用情况的功能,但你可以结合使用Docker和NVIDIA的Docker插件来查询GPU使用情况。
# 查询容器的GPU使用情况
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}\t{{.GPUMemory}}"
示例输出:
CONTAINER NAME CPU % MEM USAGE / LIMIT NET I/O BLOCK I/O PIDS GPU MEM USAGE
my_container 0.00% 0B / 0B 0B / 0B 0B / 0B 0 15360MiB
注意:以上命令可能需要根据你的具体环境和需求进行调整。
查询特定进程的GPU显存使用 步骤1: 找出容器中的进程ID 在容器内部,使用ps命令或top命令查找进程ID。例如,假设进程ID为12345。
# 在容器内部查找进程ID
ps aux | grep my_process
步骤2: 使用nvidia-smi查询进程的GPU显存使用 使用nvidia-smi命令查询进程的GPU显存使用情况。例如,查询进程ID为12345的进程的GPU显存使用情况。
# 查询进程的GPU显存使用
nvidia-smi --query-compute-apps=pid,used_memory --format=csv,noheader
示例输出:
PID Used GPU Memory
12345 15360MiB
注意:以上命令可能需要根据你的具体环境和需求进行调整。
# 查看容器中的进程
docker top 容器名称或ID
示例输出:
UID PID PPID C STIME TTY TIME CMD
root 48213 48200 0 10:23 ? 00:02:14 python train.py
root 48567 48200 0 10:25 ? 00:01:45 python inference.py
步骤2: 使用grep过滤特定进程ID的GPU使用情况 使用grep命令过滤特定进程ID的GPU使用情况。例如,假设进程ID为12345。
# 查询特定进程的GPU显存使用
nvidia-smi --query-compute-apps=pid,used_memory --format=csv,noheader | grep 12345
示例输出:
PID Used GPU Memory
12345 15360MiB
注意:以上命令可能需要根据你的具体环境和需求进行调整。
步骤3: 更复杂的查询和过滤 查询特定进程名称: 示例输出:
PID Used GPU Memory
12345 15360MiB
# 获取容器内所有进程ID
container_pids=$(docker top 容器名称或ID | awk 'NR>1 {print $2}')
# 对每个进程ID查询GPU使用
for pid in $container_pids; do
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv | grep $pid
done
步骤4: 查询容器内所有进程的GPU使用
# 获取容器内所有进程ID
container_pids=$(docker top 容器名称或ID | awk 'NR>1 {print $2}')
# 对每个进程ID查询GPU使用
for pid in $container_pids; do
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv | grep $pid
done
容器中进程关系与PID详解 在Docker容器中,每个进程都有一个唯一的进程ID(PID)。这些进程在容器内部运行,并且它们之间的父子关系与主机系统中的进程关系类似。理解这些关系有助于更好地管理和调试容器内的进程。
以下是一些关于容器中进程关系和PID的要点:
- 容器内的进程ID
- 容器内的进程ID与主机系统中的进程ID是隔离的,这意味着容器内的进程ID在容器内部是唯一的,但在主机系统中可能不是唯一的。
- 容器内的进程ID与主机系统中的进程ID之间的映射关系由Docker维护,并且可以通过Docker命令行工具查询。
- 容器内的进程ID与主机系统中的进程ID之间的映射关系可以通过Docker的网络命名空间来实现。
PID基本概念 PID (Process ID) 是操作系统分配给每个运行进程的唯一标识符。在容器中,有两种PID视角: 容器内部PID:容器内进程看到的PID,通常从1开始 宿主机PID:宿主机操作系统看到的实际PID Docker容器使用Linux的PID命名空间(namespace)实现进程隔离,使容器内的进程拥有自己的PID体系。 进程关系 容器内的进程关系遵循标准的Linux进程层次结构: 父进程(PPID): 创建当前进程的进程 子进程: 由当前进程创建的进程 PID 1: 容器内的初始进程,负责处理孤儿进程 常用进程管理命令 在容器内部使用的命令
# 查看容器内所有进程
ps aux
# 查看进程树
ps -ef --forest
# 查看特定进程信息
ps -p <PID> -o pid,ppid,cmd
# 查看进程详细信息
cat /proc/<PID>/status
# 查看进程打开的文件
ls -l /proc/<PID>/fd/
# 查看进程的环境变量
cat /proc/<PID>/environ | tr '\0' '\n'
# 查看进程的内存映射
cat /proc/<PID>/maps
# 杀死进程
kill <PID>
kill -9 <PID> # 强制杀死
# 查看进程使用的资源
top
从宿主机管理容器进程的命令
# 查看容器内的进程列表
docker top <容器名或ID>
# 查看容器内进程的宿主机PID
docker inspect --format '{{.State.Pid}}' <容器名或ID>
# 查看容器的资源使用情况
docker stats <容器名或ID>
# 进入容器执行命令
docker exec -it <容器名或ID> bash
# 向容器内进程发送信号
docker kill --signal=<信号> <容器名或ID>
# 查看宿主机上所有进程(包括容器进程)
ps aux | grep docker
# 查看特定容器的所有进程(宿主机视角)
for pid in $(docker top <容器名或ID> -aq | awk '{print $2}'); do
ps -p $pid -o pid,ppid,cmd
done