1. 引言:Docker容器技术概述

Docker是一个开源的容器化平台,它可以将应用程序及其依赖项打包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

Docker的出现解决了软件开发中的一个重要问题:环境一致性。开发人员经常遇到”在我的机器上可以运行”的问题,而Docker通过容器化技术确保了应用程序在不同环境中的一致运行。

2. Ubuntu系统下Docker的安装与配置

2.1 系统要求

在安装Docker之前,确保你的Ubuntu系统满足以下要求:

  • Ubuntu 64位版本
  • 支持的Ubuntu版本:Ubuntu 20.04 LTS, Ubuntu 18.04 LTS, Ubuntu 16.04 LTS
  • 系统内核版本不低于3.10

可以通过以下命令检查系统内核版本:

uname -r 

2.2 卸载旧版本Docker

如果系统中已经安装了旧版本的Docker,需要先卸载:

sudo apt-get remove docker docker-engine docker.io containerd runc 

2.3 安装Docker

2.3.1 使用APT仓库安装

  1. 更新APT包索引:
sudo apt-get update 
  1. 安装依赖包,允许APT通过HTTPS使用仓库:
sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release 
  1. 添加Docker的官方GPG密钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 
  1. 设置稳定的仓库:
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 
  1. 安装Docker Engine:
sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io 

2.3.2 使用脚本安装

Docker提供了一个便捷的安装脚本,可以快速安装Docker:

curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 

2.4 验证Docker安装

安装完成后,运行以下命令验证Docker是否正确安装:

sudo docker run hello-world 

如果看到以下输出,表示Docker已成功安装:

Hello from Docker! This message shows that your installation appears to be working correctly. ... 

2.5 配置Docker

2.5.1 将用户添加到docker组

默认情况下,只有root用户和docker组的用户才能运行Docker命令。将当前用户添加到docker组,可以避免每次使用Docker时都需要sudo:

sudo usermod -aG docker $USER 

注意:添加用户到docker组后,需要注销并重新登录才能使更改生效。

2.5.2 配置Docker镜像加速器

在中国大陆地区,可以使用Docker镜像加速器来提高镜像下载速度。编辑Docker配置文件:

sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://hub-mirror.c.163.com", "https://mirror.baidubce.com"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker 

3. Docker基本命令与操作

3.1 镜像相关命令

3.1.1 搜索镜像

docker search [镜像名] 

例如,搜索Ubuntu镜像:

docker search ubuntu 

3.1.2 拉取镜像

docker pull [镜像名]:[标签] 

例如,拉取Ubuntu 20.04镜像:

docker pull ubuntu:20.04 

3.1.3 查看本地镜像

docker images 

或者

docker image ls 

3.1.4 删除本地镜像

docker rmi [镜像ID或镜像名:标签] 

例如:

docker rmi ubuntu:20.04 

3.2 容器相关命令

3.2.1 运行容器

docker run [选项] [镜像名]:[标签] [命令] 

常用选项:

  • -d:后台运行容器
  • -i:以交互模式运行容器
  • -t:为容器分配一个伪输入终端
  • --name:为容器指定一个名称
  • -p:将容器端口映射到主机端口
  • -v:将主机目录挂载到容器
  • -e:设置环境变量

例如,运行一个Ubuntu容器并进入交互式终端:

docker run -it --name my-ubuntu ubuntu:20.04 /bin/bash 

3.2.2 查看运行中的容器

docker ps 

或者

docker container ls 

3.2.3 查看所有容器(包括已停止的)

docker ps -a 

3.2.4 停止容器

docker stop [容器ID或容器名] 

例如:

docker stop my-ubuntu 

3.2.5 启动已停止的容器

docker start [容器ID或容器名] 

例如:

docker start my-ubuntu 

3.2.6 重启容器

docker restart [容器ID或容器名] 

例如:

docker restart my-ubuntu 

3.2.7 删除容器

docker rm [容器ID或容器名] 

例如:

docker rm my-ubuntu 

3.2.8 进入运行中的容器

docker exec -it [容器ID或容器名] /bin/bash 

例如:

docker exec -it my-ubuntu /bin/bash 

3.2.9 查看容器日志

docker logs [容器ID或容器名] 

例如:

docker logs my-ubuntu 

4. Docker镜像的创建与管理

4.1 使用Dockerfile创建镜像

Dockerfile是一个文本文件,包含了构建Docker镜像的所有命令。下面是一个简单的Dockerfile示例:

# 基础镜像 FROM ubuntu:20.04 # 维护者信息 MAINTAINER Your Name <your.email@example.com> # 设置环境变量 ENV DEBIAN_FRONTEND=noninteractive # 更新软件包列表并安装软件 RUN apt-get update && apt-get install -y nginx curl && rm -rf /var/lib/apt/lists/* # 复制文件到容器中 COPY index.html /var/www/html/ # 暴露端口 EXPOSE 80 # 启动nginx CMD ["nginx", "-g", "daemon off;"] 

4.2 构建镜像

在Dockerfile所在目录下,运行以下命令构建镜像:

docker build -t my-nginx:1.0 . 

其中:

  • -t:指定镜像的名称和标签
  • .:指定构建上下文,当前目录

4.3 镜像的导出与导入

4.3.1 导出镜像

docker save -o my-nginx-1.0.tar my-nginx:1.0 

4.3.2 导入镜像

docker load -i my-nginx-1.0.tar 

4.4 镜像的推送与拉取

4.4.1 登录到Docker Hub

docker login 

4.4.2 标记镜像

docker tag my-nginx:1.0 your-dockerhub-username/my-nginx:1.0 

4.4.3 推送镜像

docker push your-dockerhub-username/my-nginx:1.0 

4.4.4 拉取镜像

docker pull your-dockerhub-username/my-nginx:1.0 

5. Docker容器的网络配置

5.1 Docker网络类型

Docker提供了多种网络类型,包括:

  • bridge:默认网络类型,容器通过桥接方式连接到主机网络
  • host:容器与主机共享网络命名空间
  • none:容器没有网络接口
  • overlay:用于Swarm集群中的容器通信
  • macvlan:为容器分配MAC地址,使其显示为物理网络上的设备
  • 自定义网络:用户创建的网络

5.2 查看网络

docker network ls 

5.3 创建自定义网络

docker network create --driver bridge my-network 

5.4 将容器连接到网络

5.4.1 在创建容器时连接到网络

docker run -d --name my-container --network my-network nginx 

5.4.2 将已存在的容器连接到网络

docker network connect my-network my-container 

5.5 断开容器与网络的连接

docker network disconnect my-network my-container 

5.6 查看网络详情

docker network inspect my-network 

5.7 删除网络

docker network rm my-network 

5.8 端口映射

将容器端口映射到主机端口:

docker run -d -p 8080:80 --name my-nginx nginx 

这会将容器的80端口映射到主机的8080端口。

6. Docker数据卷的使用

6.1 数据卷概述

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS(联合文件系统),可以提供很多有用的特性:

  • 数据卷可以在容器之间共享和重用
  • 对数据卷的修改会立马生效
  • 对数据卷的更新不会影响镜像
  • 数据卷默认会一直存在,即使容器被删除

6.2 创建数据卷

docker volume create my-volume 

6.3 查看数据卷

docker volume ls 

6.4 查看数据卷详情

docker volume inspect my-volume 

6.5 使用数据卷

6.5.1 在创建容器时挂载数据卷

docker run -d -v my-volume:/app --name my-container nginx 

6.5.2 挂载主机目录到容器

docker run -d -v /host/path:/container/path --name my-container nginx 

6.5.3 只读挂载

docker run -d -v my-volume:/app:ro --name my-container nginx 

6.6 删除数据卷

docker volume rm my-volume 

6.7 清理未使用的数据卷

docker volume prune 

7. Docker Compose的使用

7.1 Docker Compose概述

Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。通过Compose,你可以使用YAML文件来配置应用程序需要的所有服务,然后使用一个命令,从YAML文件配置中创建并启动所有服务。

7.2 安装Docker Compose

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose 

7.3 验证Docker Compose安装

docker-compose --version 

7.4 Docker Compose文件示例

创建一个名为docker-compose.yml的文件:

version: '3' services: web: build: . ports: - "5000:5000" volumes: - .:/code - logvolume01:/var/log links: - redis redis: image: redis volumes: - logvolume01:/data volumes: logvolume01: {} 

7.5 Docker Compose常用命令

7.5.1 启动服务

docker-compose up 

后台运行:

docker-compose up -d 

7.5.2 停止服务

docker-compose down 

7.5.3 查看服务状态

docker-compose ps 

7.5.4 查看服务日志

docker-compose logs 

7.5.5 构建或重新构建服务

docker-compose build 

7.5.6 启动服务

docker-compose start 

7.5.7 停止服务

docker-compose stop 

7.5.8 重启服务

docker-compose restart 

8. 实战案例:使用Docker部署应用

8.1 部署一个简单的Web应用

8.1.1 创建项目目录结构

mkdir my-web-app cd my-web-app mkdir app 

8.1.2 创建Flask应用

app目录下创建app.py文件:

from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return "Hello, Dockerized World!" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) 

8.1.3 创建requirements.txt

在项目根目录下创建requirements.txt文件:

Flask==2.0.1 

8.1.4 创建Dockerfile

在项目根目录下创建Dockerfile文件:

# 基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 复制requirements.txt文件 COPY requirements.txt . # 安装依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY ./app /app # 暴露端口 EXPOSE 5000 # 运行应用 CMD ["python", "app.py"] 

8.1.5 构建镜像

docker build -t my-web-app . 

8.1.6 运行容器

docker run -d -p 5000:5000 --name my-web-app-container my-web-app 

8.1.7 测试应用

访问http://localhost:5000,应该能看到”Hello, Dockerized World!“的输出。

8.2 使用Docker Compose部署多容器应用

8.2.1 创建项目目录结构

mkdir my-multi-app cd my-multi-app mkdir web mkdir db 

8.2.2 创建Web应用

web目录下创建app.py文件:

from flask import Flask, jsonify import psycopg2 import os app = Flask(__name__) def get_db_connection(): conn = psycopg2.connect( host="db", database="mydb", user=os.environ['DB_USER'], password=os.environ['DB_PASSWORD'] ) return conn @app.route('/') def hello(): return "Hello, Multi-container World!" @app.route('/users') def get_users(): conn = get_db_connection() cur = conn.cursor() cur.execute('SELECT * FROM users;') users = cur.fetchall() cur.close() conn.close() return jsonify(users) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) 

web目录下创建requirements.txt文件:

Flask==2.0.1 psycopg2-binary==2.9.1 

web目录下创建Dockerfile文件:

# 基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 复制requirements.txt文件 COPY requirements.txt . # 安装依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . . # 暴露端口 EXPOSE 5000 # 运行应用 CMD ["python", "app.py"] 

8.2.3 创建数据库初始化脚本

db目录下创建init.sql文件:

CREATE DATABASE mydb; c mydb; CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL ); INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com'); INSERT INTO users (name, email) VALUES ('Jane Smith', 'jane@example.com'); 

8.2.4 创建Docker Compose文件

在项目根目录下创建docker-compose.yml文件:

version: '3' services: web: build: ./web ports: - "5000:5000" environment: - DB_USER=postgres - DB_PASSWORD=example depends_on: - db networks: - app-network db: image: postgres:13 environment: - POSTGRES_PASSWORD=example volumes: - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql - postgres_data:/var/lib/postgresql/data networks: - app-network volumes: postgres_data: networks: app-network: driver: bridge 

8.2.5 启动应用

docker-compose up -d 

8.2.6 测试应用

  1. 访问http://localhost:5000,应该能看到”Hello, Multi-container World!“的输出。
  2. 访问http://localhost:5000/users,应该能看到数据库中的用户列表。

9. Docker在解决开发环境不一致问题中的应用

9.1 开发环境一致性问题

在软件开发过程中,开发环境不一致是一个常见问题。不同的开发人员可能使用不同的操作系统、不同的软件版本或不同的配置,这可能导致”在我的机器上可以运行”的问题。

9.2 使用Docker解决开发环境一致性问题

Docker通过容器化技术提供了一种解决开发环境一致性问题的有效方法。以下是具体实施步骤:

9.2.1 创建开发环境镜像

创建一个包含所有开发工具和依赖的Docker镜像。例如,对于Python开发环境:

# 基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 安装系统依赖 RUN apt-get update && apt-get install -y git vim && rm -rf /var/lib/apt/lists/* # 复制requirements.txt文件 COPY requirements.txt . # 安装Python依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . . # 设置环境变量 ENV PYTHONPATH=/app # 默认命令 CMD ["bash"] 

9.2.2 使用Docker Compose管理开发环境

创建一个docker-compose.yml文件,定义开发环境所需的所有服务:

version: '3' services: app: build: . volumes: - .:/app environment: - FLASK_ENV=development ports: - "5000:5000" depends_on: - db networks: - dev-network db: image: postgres:13 environment: - POSTGRES_PASSWORD=example volumes: - postgres_data:/var/lib/postgresql/data networks: - dev-network volumes: postgres_data: networks: dev-network: driver: bridge 

9.2.3 创建开发脚本

创建一个dev.sh脚本,简化开发环境的启动:

#!/bin/bash # 启动开发环境 docker-compose up -d # 进入应用容器 docker-compose exec app bash 

9.2.4 使用VS Code Remote Development

VS Code提供了Remote Development扩展,允许开发者直接在容器中进行开发。以下是配置步骤:

  1. 在项目根目录创建.devcontainer目录。
  2. .devcontainer目录下创建devcontainer.json文件:
{ "name": "Python Development", "dockerFile": "../Dockerfile", "context": "..", "appPort": 5000, "extensions": [ "ms-python.python" ], "settings": { "python.pythonPath": "/usr/local/bin/python", "python.linting.pylintEnabled": true, "python.linting.enabled": true } } 
  1. 在VS Code中安装Remote Development扩展。
  2. 使用VS Code打开项目,然后点击左下角的绿色远程连接按钮,选择”Reopen in Container”。

9.3 CI/CD中的Docker应用

Docker也可以在CI/CD流程中发挥作用,确保构建、测试和生产环境的一致性。

9.3.1 使用GitHub Actions和Docker

创建一个.github/workflows/ci.yml文件:

name: CI on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Build the Docker image run: docker build . --file Dockerfile --tag my-app:$(date +%s) - name: Run tests run: docker run my-app:$(date +%s) python -m pytest - name: Login to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Push to Docker Hub run: | docker tag my-app:$(date +%s) ${{ secrets.DOCKER_HUB_USERNAME }}/my-app:latest docker push ${{ secrets.DOCKER_HUB_USERNAME }}/my-app:latest 

10. 最佳实践和注意事项

10.1 Dockerfile最佳实践

  1. 使用多阶段构建:减少最终镜像的大小。
# 构建阶段 FROM node:14 AS build WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 生产阶段 FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] 
  1. 使用.dockerignore文件:排除不必要的文件和目录。
.git .gitignore node_modules npm-debug.log Dockerfile .dockerignore 
  1. 合并RUN命令:减少镜像层数。
# 不推荐 RUN apt-get update RUN apt-get install -y nginx RUN rm -rf /var/lib/apt/lists/* # 推荐 RUN apt-get update && apt-get install -y nginx && rm -rf /var/lib/apt/lists/* 
  1. 使用特定版本的镜像:避免使用latest标签。
# 不推荐 FROM ubuntu:latest # 推荐 FROM ubuntu:20.04 
  1. 以非root用户运行:提高安全性。
FROM node:14 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN groupadd -r appuser && useradd -r -g appuser appuser USER appuser CMD ["node", "app.js"] 

10.2 容器安全最佳实践

  1. 不要在容器中存储敏感数据:使用环境变量或密钥管理服务。

  2. 限制容器资源:防止容器耗尽系统资源。

docker run -d --memory="512m" --cpus="1.0" my-app 
  1. 定期更新基础镜像:修复已知的安全漏洞。

  2. 扫描镜像中的漏洞:使用工具如Docker Security Scanning或Clair。

  3. 使用只读根文件系统:防止攻击者修改文件系统。

docker run --read-only my-app 

10.3 性能优化

  1. 使用缓存层:合理排序Dockerfile中的指令,充分利用缓存。

  2. 清理不必要的包和缓存:减少镜像大小。

RUN apt-get update && apt-get install -y nginx && rm -rf /var/lib/apt/lists/* && apt-get clean 
  1. 使用多阶段构建:减少最终镜像的大小。

  2. 选择合适的基础镜像:alpine版本通常比完整版本小得多。

  3. 使用.volume:将频繁变化的数据存储在卷中,而不是在镜像中。

10.4 故障排除

  1. 查看容器日志
docker logs [容器ID或容器名] 
  1. 检查容器状态
docker inspect [容器ID或容器名] 
  1. 在容器中运行命令
docker exec [容器ID或容器名] [命令] 
  1. 查看Docker系统信息
docker info 
  1. 清理Docker系统
docker system prune -a 

11. 结论

Docker容器技术为软件开发和部署带来了革命性的变化。通过本文的学习,你应该已经掌握了在Ubuntu系统下安装、配置和使用Docker的基本技能,包括创建和管理镜像、运行和管理容器、配置网络和数据卷、使用Docker Compose管理多容器应用,以及如何将Docker应用于解决开发环境不一致问题。

Docker不仅仅是一种技术,更是一种文化和方法论。它提倡”构建一次,到处运行”的理念,极大地简化了软件的开发、测试和部署流程。通过采用Docker容器化技术,开发团队可以更高效地协作,减少环境问题,提高软件交付的速度和质量。

随着云原生技术的发展,Docker已经成为现代软件开发和运维不可或缺的工具。希望本文能够帮助你全面掌握Docker容器技术,并在实际工作中灵活应用,解决实际问题。