Docker作为当前最流行的容器化技术,已经成为开发者和运维人员的标配工具。它通过操作系统级别的虚拟化技术,将应用程序及其依赖打包到一个轻量级、可移植的容器中。相比传统虚拟机,Docker容器启动更快、资源占用更少,且能确保环境一致性,彻底解决了"在我机器上能跑"的经典问题。
在Ubuntu上使用Docker尤其方便,因为Ubuntu作为最流行的Linux发行版之一,对Docker有原生支持。无论是开发环境搭建、微服务部署,还是机器学习项目,Docker都能提供标准化的运行环境。我曾在多个项目中遇到环境配置问题,自从全面采用Docker后,这些问题都迎刃而解。
在开始安装前,请确保你的Ubuntu系统满足以下要求:
提示:使用
lsb_release -a命令可以查看当前Ubuntu版本信息。如果是旧版本,建议先升级系统。
如果你之前安装过旧版Docker,建议先彻底清理:
bash复制sudo apt-get remove docker docker-engine docker.io containerd runc
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
这样可以避免版本冲突导致的问题。我曾经因为没清理干净旧版本,导致新安装的Docker无法正常启动。
首先更新apt索引并安装必要的依赖包:
bash复制sudo apt update
sudo apt install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release \
software-properties-common
然后添加Docker的官方GPG密钥和APT仓库。为了提高国内用户的下载速度,这里使用清华源:
bash复制# 添加Docker的官方GPG密钥
curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加Docker的官方APT仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
更新apt索引并安装最新版Docker:
bash复制sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
安装完成后验证版本:
bash复制sudo docker --version
# 输出示例:Docker version 20.10.17, build 100c701
默认情况下,运行Docker命令需要sudo权限。为了方便使用,可以将当前用户添加到docker组:
bash复制sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
现在可以不用sudo测试Docker是否正常工作:
bash复制docker run hello-world
如果看到"Hello from Docker!"的消息,说明安装成功。
注意:如果遇到权限问题,可以尝试:
bash复制sudo chmod o+rw /var/run/docker.sock
Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。从Docker 20.10.0开始,Compose已经作为插件集成到Docker CLI中:
bash复制sudo apt install -y docker-compose-plugin
验证安装:
bash复制docker compose version
# 输出示例:Docker Compose version v2.6.0
如果你的Ubuntu系统有NVIDIA显卡,并且需要在Docker容器中使用GPU加速(如深度学习训练),需要安装NVIDIA容器工具包:
bash复制curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
&& curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
bash复制sudo apt update
sudo apt install -y nvidia-container-toolkit
bash复制sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
bash复制docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi
如果看到显卡信息输出,说明配置成功。
bash复制# 搜索镜像
docker search ubuntu
# 拉取镜像
docker pull ubuntu:20.04
# 列出本地镜像
docker images
# 删除镜像
docker rmi ubuntu:20.04
# 构建镜像(需要Dockerfile)
docker build -t my-image:1.0 .
# 保存镜像为tar文件
docker save -o ubuntu.tar ubuntu:20.04
# 从tar文件加载镜像
docker load -i ubuntu.tar
bash复制# 运行容器
docker run -it --name my-container ubuntu:20.04 /bin/bash
# 列出运行中的容器
docker ps
# 列出所有容器
docker ps -a
# 启动/停止/重启容器
docker start my-container
docker stop my-container
docker restart my-container
# 进入运行中的容器
docker exec -it my-container /bin/bash
# 删除容器
docker rm my-container
# 查看容器日志
docker logs -f my-container
# 查看容器资源使用
docker stats my-container
# 复制文件
docker cp host_file.txt my-container:/path/in/container
docker cp my-container:/path/in/container/file.txt host_file.txt
bash复制# 创建网络
docker network create my-network
# 运行容器并连接网络
docker run -d --name web --network my-network nginx
# 创建卷
docker volume create my-volume
# 使用卷
docker run -v my-volume:/data ubuntu
Docker Compose通过YAML文件定义多容器应用。创建一个docker-compose.yml文件:
yaml复制version: '3.8'
services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
networks:
- my-network
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- db-data:/var/lib/mysql
networks:
- my-network
volumes:
db-data:
networks:
my-network:
常用命令:
bash复制# 启动服务
docker compose up -d
# 停止服务
docker compose down
# 构建镜像
docker compose build
# 查看服务状态
docker compose ps
# 查看日志
docker compose logs -f
Dockerfile是构建Docker镜像的蓝图。下面是一个完整的示例:
dockerfile复制# 使用官方ROS基础镜像
FROM ros:humble-ros-base-jammy
# 设置工作目录
WORKDIR /workspace
# 安装系统依赖
RUN apt update && apt install -y \
build-essential \
cmake \
git \
python3-pip \
python3-rosdep \
python3-colcon-common-extensions \
libopencv-dev \
&& rm -rf /var/lib/apt/lists/*
# 初始化rosdep
RUN rosdep init && rosdep update
# 安装ROS包
RUN apt update && apt install -y \
ros-humble-vision-opencv \
ros-humble-tf2 \
&& rm -rf /var/lib/apt/lists/*
# 创建工作空间
RUN mkdir -p /workspace/src
# 复制源代码(构建时通过上下文复制)
COPY ./src /workspace/src
# 安装Python依赖
COPY requirements.txt .
RUN pip install -r requirements.txt
# 构建工作空间
RUN cd /workspace && \
rosdep install -y --from-paths src --ignore-src --rosdistro humble && \
colcon build
# 设置环境变量
ENV ROS_DOMAIN_ID=42
ENV RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
# 设置入口点
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["bash"]
如果遇到"Got permission denied"错误:
bash复制sudo usermod -aG docker $USER
newgrp docker
如果仍然有问题:
bash复制sudo chmod 666 /var/run/docker.sock
可以配置国内镜像加速器。创建或修改/etc/docker/daemon.json:
json复制{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
然后重启Docker:
bash复制sudo systemctl daemon-reload
sudo systemctl restart docker
检查DNS配置:
bash复制sudo vim /etc/docker/daemon.json
添加:
json复制{
"dns": ["8.8.8.8", "114.114.114.114"]
}
重启Docker服务。
Docker会占用大量磁盘空间。清理无用资源:
bash复制# 删除所有停止的容器
docker container prune
# 删除所有未被使用的镜像
docker image prune -a
# 删除所有未被使用的网络
docker network prune
# 删除所有未被使用的卷
docker volume prune
# 一键清理所有
docker system prune -a
使用.dockerignore文件:类似.gitignore,避免不必要的文件被复制到构建上下文
多阶段构建:减少最终镜像大小
dockerfile复制FROM golang:1.18 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]
合理使用缓存:将不常变化的指令放在前面
避免使用root用户:在容器中使用非root用户更安全
dockerfile复制RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser
bash复制docker run -it --memory="512m" --cpus="1.5" ubuntu
定期更新镜像:使用docker scan检查镜像漏洞
最小化镜像:使用Alpine等轻量级基础镜像
不存储敏感信息:使用Docker secrets或环境变量
只开放必要端口:避免-p 80-90:80-90这样的范围映射
使用只读文件系统:对于不需要写入的容器
bash复制docker run --read-only -v /tmp:/tmp alpine
bash复制docker run --cap-drop all --cap-add NET_BIND_SERVICE nginx
bash复制# 实时监控
docker stats
# 查看容器详细信息
docker inspect container_name
# 查看容器资源使用历史
docker stats --no-stream > stats.log
bash复制# 查看日志
docker logs container_name
# 跟踪日志
docker logs -f container_name
# 限制日志大小
docker run --log-opt max-size=10m --log-opt max-file=3 nginx
为团队创建一致的开发环境:
dockerfile复制FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
使用Compose编排多个服务:
yaml复制version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
depends_on:
- backend
backend:
build: ./backend
ports:
- "8000:8000"
environment:
DB_HOST: db
db:
image: postgres:13
environment:
POSTGRES_PASSWORD: example
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
在GitHub Actions中使用Docker:
yaml复制name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Docker image
run: docker build -t myapp .
- name: Run tests
run: docker run myapp npm test
BuildKit是下一代镜像构建工具,性能更好:
bash复制DOCKER_BUILDKIT=1 docker build -t myapp .
构建支持多种CPU架构的镜像:
bash复制docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t myapp .
通过Python控制Docker:
python复制import docker
client = docker.from_env()
client.containers.run("ubuntu", "echo hello world")
bash复制# 检查容器进程
docker top container_name
# 检查容器文件系统
docker diff container_name
# 检查容器网络
docker exec container_name ip a
定期清理可以节省大量磁盘空间:
bash复制# 删除所有停止的容器
docker container prune
# 删除所有未被使用的镜像
docker image prune -a
# 删除所有未被使用的网络
docker network prune
# 删除所有未被使用的卷
docker volume prune
# 一键清理所有
docker system prune -a
对于更精确的清理,可以使用:
bash复制# 删除超过一周的容器
docker container prune --filter "until=168h"
# 删除特定标签的镜像
docker image prune --filter "label=maintainer=john"
bash复制# 提交容器为镜像
docker commit container_name backup-image
# 保存镜像为tar文件
docker save -o backup.tar backup-image
bash复制# 创建备份容器
docker run --rm -v db-data:/volume -v $(pwd):/backup alpine \
tar cvf /backup/db-backup.tar /volume
bash复制# 从tar文件恢复镜像
docker load -i backup.tar
# 恢复卷数据
docker run --rm -v db-data:/volume -v $(pwd):/backup alpine \
tar xvf /backup/db-backup.tar -C /volume --strip 1
bash复制# 初始化Swarm
docker swarm init
# 部署服务
docker service create --name web --replicas 3 -p 80:80 nginx
# 查看服务
docker service ls
在Dockerfile或Compose文件中定义健康检查:
dockerfile复制HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/ || exit 1
或在Compose中:
yaml复制healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 3s
retries: 3
使用Docker内置工具扫描镜像漏洞:
bash复制docker scan ubuntu:20.04
集成到CI/CD流程:
yaml复制- name: Scan image
run: docker scan --file Dockerfile --severity high myapp
创建自定义网络并配置:
bash复制# 创建自定义网络
docker network create --driver=bridge --subnet=172.28.0.0/16 my-net
# 运行容器并指定IP
docker run --network=my-net --ip=172.28.5.3 -d nginx
限制容器资源使用:
bash复制# 限制内存和CPU
docker run -it --memory="512m" --cpus="1.5" ubuntu
# 限制IO
docker run -it --device-read-bps /dev/sda:1mb ubuntu
在Compose中:
yaml复制services:
web:
image: nginx
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
配置日志驱动和选项:
bash复制docker run --log-driver=json-file --log-opt max-size=10m nginx
查看日志:
bash复制# 显示最后100行
docker logs --tail 100 container_name
# 显示特定时间后的日志
docker logs --since 2023-01-01T00:00:00 container_name
# 显示特定时间范围内的日志
docker logs --since 2023-01-01T00:00:00 --until 2023-01-02T00:00:00 container_name
查看当前存储驱动:
bash复制docker info | grep "Storage Driver"
修改存储驱动(在/etc/docker/daemon.json中):
json复制{
"storage-driver": "overlay2"
}
创建和管理卷:
bash复制# 创建卷
docker volume create my-vol
# 查看卷详情
docker volume inspect my-vol
# 删除卷
docker volume rm my-vol
Docker支持多种网络驱动:
bash复制# 创建自定义bridge网络
docker network create -d bridge --subnet 192.168.100.0/24 --gateway 192.168.100.1 my-bridge
# 创建macvlan网络
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
my-macvlan
bash复制# 检查容器日志
docker logs container_name
# 检查容器进程
docker top container_name
# 检查容器文件系统变化
docker diff container_name
# 检查容器网络配置
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name
在容器中安装调试工具:
dockerfile复制FROM alpine
RUN apk add --no-cache curl bind-tools
或者临时进入容器调试:
bash复制docker exec -it container_name /bin/sh
单一进程原则:每个容器只运行一个主进程
最小化镜像:移除不必要的依赖和文件
使用非root用户:提高安全性
正确处理信号:确保容器能优雅停止
健康检查:监控容器健康状态
资源限制:防止容器占用过多资源
环境分离:使用不同配置区分环境
版本控制:为镜像打上语义化版本标签
扫描漏洞:定期扫描镜像中的安全漏洞
文档化:为镜像和容器编写清晰的文档
bash复制# 实时监控
docker stats
# 详细性能数据
docker stats --format "table {{.Container}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# 导出性能数据
docker stats --no-stream > stats.log
限制资源:为容器设置合理的CPU和内存限制
使用轻量级基础镜像:如Alpine代替Ubuntu
减少层数:合并RUN指令减少镜像层
使用多阶段构建:减少最终镜像大小
避免不必要的卷:减少IO开销
调整存储驱动:根据工作负载选择合适的驱动
优化网络配置:选择合适的网络驱动
使用缓存:利用Docker构建缓存
bash复制# 启用用户命名空间
dockerd --userns-remap=default
# 启用seccomp
dockerd --seccomp-profile=/etc/docker/seccomp/default.json
# 启用AppArmor
docker run --security-opt apparmor=docker-default nginx
bash复制# 扫描本地镜像
docker scan ubuntu:20.04
# 集成到CI/CD
docker scan --file Dockerfile --severity high myapp
yaml复制name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: user/app:latest
groovy复制pipeline {
agent any
stages {
stage('Build') {
steps {
script {
docker.build("myapp:${env.BUILD_ID}")
}
}
}
stage('Test') {
steps {
script {
docker.image("myapp:${env.BUILD_ID}").inside {
sh 'npm test'
}
}
}
}
stage('Deploy') {
steps {
script {
docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') {
docker.image("myapp:${env.BUILD_ID}").push('latest')
}
}
}
}
}
}
我曾参与一个将传统Java应用迁移到Docker的项目。通过以下步骤实现:
迁移后,部署时间从2小时缩短到5分钟,环境问题减少了90%。
在一个电商项目中,我们使用Docker Compose编排了12个微服务:
这种架构提高了开发效率,使团队能够独立部署服务。
官方文档:
书籍:
在线课程:
社区:
工具:
容器技术仍在快速发展,以下是一些值得关注的趋势:
在多年的Docker使用中,我总结了以下经验教训:
曾经因为没有设置资源限制,导致一个容器占用了全部内存,使整个主机崩溃。从那以后,我养成了为每个容器设置合理限制的习惯。
与传统虚拟机的对比:
| 特性 | Docker容器 | 传统虚拟机 |
|---|---|---|
| 启动时间 | 秒级 | 分钟级 |
| 资源占用 | 低(MB级) | 高(GB级) |
| 性能损失 | 几乎无 | 明显 |
| 隔离性 | 进程级别 | 硬件级别 |
| 镜像大小 | 通常较小 | 通常较大 |
| 部署密度 | 高 | 低 |
| 移植性 | 强 | 弱 |
在企业环境中使用Docker的建议:
检查步骤:
docker logs container_namedocker inspect -f '{{.State.ExitCode}}' container_namedocker run -it image_name /bin/sh检查步骤:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_namedocker exec container_name ping target_hostdocker exec container_name cat /etc/resolv.conf检查步骤:
docker stats container_namedocker exec container_name topdocker exec container_name ps aux使用Docker实现跨平台开发:
bash复制docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix ubuntu
bash复制docker buildx build --platform linux/amd64,linux/arm64 -t myapp .
经过多年的Docker使用,我发现最大的价值在于它带来的标准化和可重复性。无论是个人的开发环境,还是企业的生产部署,Docker都能显著提高效率和可靠性。希望这份指南能帮助你顺利开始Docker之旅。