引言
Docker 是一种轻量级的容器化技术,广泛应用于应用程序的打包、分发和部署。本文将介绍 Docker 的基本概念、常用命令以及如何将本地环境封装到 Docker 中,帮助读者快速上手 Docker。
一、Docker 基本概念
Docker 的核心概念包括 镜像、容器 和 仓库。
1. 镜像 (Image)
操作系统分为 内核空间 和 用户空间。对于 Linux 系统,在内核启动后,会加载 root 文件系统为其提供用户空间支持。Docker 镜像类似于一个 root 文件系统,它是一个特殊的文件系统,包含了容器运行时所需的程序、库、资源、配置等文件,同时还包含了一些运行时的配置参数(如匿名卷、环境变量、用户等)。镜像本身是不可变的,其内容在构建完成后不会改变。
2. 容器 (Container)
镜像(Image)和容器(Container)的关系类似于面向对象程序设计中的 类 和 对象。镜像是静态的定义,而容器是镜像的动态运行实例。通过镜像,可以创建多个独立的容器实例,每个容器都相互隔离。
3. 仓库 (Repository)
镜像构建完成后,可以在当前宿主机上通过启动容器运行,但如果需要在其他服务器上使用,就需要一个集中的存储和分发服务。Docker Registry 就是这样一个服务。一个 Docker Registry 中可以包含多个 仓库,每个仓库可以包含多个 标签,每个标签对应一个镜像版本。通过 <仓库名>:<标签> 的方式可以指定镜像的具体版本。
常用的 Docker Registry 服务包括:
- Docker Hub
- GitHub Container Registry (ghcr.io)
- Google Container Registry
在国内,由于网络原因,访问 Docker Hub 可能较慢,因此可以使用国内提供的 镜像加速器(Registry Mirror)来提高下载速度。
二、Docker 镜像的使用
1. 获取镜像
从 Docker 镜像仓库获取镜像的命令如下:
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
2. 使用 Dockerfile 定制镜像
镜像的定制实际上是通过定制每一层的配置和文件来实现的。可以将每一层的修改、安装、构建、操作写入一个脚本文件 Dockerfile 来定制镜像。具体步骤如下:
-
指定基础镜像
使用FROM指令指定基础镜像。例如:FROM ubuntu:20.04特殊的基础镜像
scratch表示空白镜像,用于从零开始构建镜像。 -
运行命令
使用RUN指令指定命令行工具。每个RUN指令都会新建一层。为了避免不必要的层,可以将多个命令用&&连接在同一层中。例如:RUN apt-get update && apt-get install -y nginx -
构建镜像
在Dockerfile文件所在目录执行以下命令:
docker build -t <镜像名>:<标签>
-t, --tag: 为构建的镜像指定名称和标签
三、常用 Docker 命令
| 命令 | 描述 |
|---|---|
docker images | 列出本地镜像 |
docker ps | 列出正在运行的容器 |
docker stop <容器ID或容器名称> | 停止容器 |
docker rm <容器ID或容器名称> | 删除容器 |
docker rmi <镜像ID或镜像名称> | 删除镜像 |
docker logs <容器ID或容器名称> | 查看容器日志 |
docker run | 创建并启动一个新的容器(如果镜像不存在,会先拉取镜像) |
docker exec | 在已运行的容器中执行命令 |
1. docker run 参数详解
示例:
sudo docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway --gpus=all -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.nju.edu.cn/open-webui/open-webui:main
-d:表示以“后台模式”(detached mode)运行容器。容器会在后台运行,不会占用终端。-p 3000:8080:将容器的 8080 端口映射到主机的 3000 端口。这样,访问主机的localhost:3000就可以访问容器内的服务。--add-host=host.docker.internal:host-gateway:向容器的/etc/hosts文件中添加一条主机映射,将host.docker.internal解析为 Docker 主机的网关地址。在 Docker 中,host.docker.internal是一个特殊的 DNS 名称,用于从容器内部访问宿主机的服务。--gpus=all:允许容器使用主机的 所有 GPU 资源。-v ollama:/root/.ollama:将主机的ollama卷挂载到容器内的/root/.ollama目录。用于持久化存储数据。-v open-webui:/app/backend/data:将主机的open-webui卷挂载到容器内的/app/backend/data目录。同样用于持久化存储数据。--name open-webui:为容器指定一个名称open-webui,方便后续管理和操作。--restart always:设置容器的重启策略为always。如果容器意外停止,Docker 会自动重新启动它。重启时机:在重启 Docker 时,自动启动容器。ghcr.nju.edu.cn/open-webui/open-webui:main:指定要运行的 Docker 镜像及其版本。
2. docker run 和 docker start 的区别
docker run:用于创建并启动一个新的容器。如果镜像不存在,会先拉取镜像。docker start:用于启动已存在的容器。它不会创建新的容器,而是重新启动一个已经存在但停止的容器。
3. 查看容器日志
可以实时刷新日志:
sudo docker logs container_name -f
显示日志时间戳:
sudo docker logs container_name --timestamps
4. 停止容器
-
停止所有容器:
sudo docker ps -q | sudo xargs docker stop
四、使用加速器
在国内,Docker 下载镜像可能会比较慢。通过使用加速器可以显著提高下载速度。例如,阿里云提供的加速器可以通过以下步骤配置:
- 创建
/etc/docker/daemon.json文件:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://<你的阿里云加速器地址>.mirror.aliyuncs.com"]
}
EOF
- 重新加载 Docker 配置并重启服务:
sudo systemctl daemon-reload
sudo systemctl restart docker
五、将本地python环境封装到 Docker
1. 在 Docker 中安装 Anaconda 镜像
- 搜索 Anaconda 镜像:
docker search anaconda
- 拉取镜像:
docker pull continuumio/anaconda3
- 运行镜像:
docker run -i -t continuumio/anaconda3 /bin/bash
2. 封装本地 Anaconda 环境
在 Docker 环境下
查找 Anaconda 环境:
# anaconda: /opt/conda/bin/anaconda
whereis anaconda
然后这里拷贝的不应该是直接结果的 anaconda 路径,应该往上找两级下面的 conda/envs。
在本地环境下
复制本地环境到 Docker 容器内:
# docker cp /home/zxxx/anaconda3/envs/torch c6ebff84b63f:/opt/conda/envs
docker cp your_path/anaconda3/envs/env_name docker_name:anaconda_path/envs
docker cp 中的 docker_name 应该是 CONTAINER ID,不是 Image ID。
将 Docker 容器保存为镜像:
# docker commit -a sunjk -m "save torch env" c6ebff84b63f anaconda
docker commit -a [author] -m [instruction] docker_name image_name
查看镜像:
docker image ls
将镜像压为压缩包:
docker save image_name -o compressed_package_name
3. Docker 镜像导入
- 将压缩包拷贝到另一台主机。
- 导入 Docker 环境:
docker load -i conda_zip
- 启动 Docker:
docker run -i -t image_name /bin/bash
-it: 交互式运行容器,分配一个伪终端。
七、非 root 用户运行 Docker
- 创建
docker组(如果不存在):
sudo groupadd docker
- 将当前用户添加到
docker组:
sudo usermod -aG docker $USER
- 重新登录以应用组更改(或重启系统):
newgrp docker
- 检查 Docker 是否可以非 root 运行:
docker run hello-world