docker 容器技术使得开发测试非常方便,自 2013 年发布至今,一直广受瞩目。软件开发最大的麻烦事之一,就是环境配置。虚拟机虽然能够解决上面问题,但是有如下缺点:1.资源占用多 ,2.冗余步骤多 ,3. 启动慢 ;由于虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。 或者说,在正常进程的外面套了一个保护层 。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。由于容器是进程级别的,相比虚拟机有很多优势。1. 启动快 , 2, 资源占用少 ,3. 体积小 . 总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。 它是目前最流行的 Linux 容器解决方案。下面介绍2020年08月以后,如何安装使用 docker,本篇以 Windows 10 wsl 2 Ubuntu-20.04 为例。
Docker 的主要用途,目前有三大类: (1)提供一次性的环境。 比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境;
(2)提供弹性的云服务。 因为 Docker 容器可以随开随关,很适合动态扩容和缩容;
(3)组建微服务架构。 通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
docker 安装 在线安装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 sudo apt-get update sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add - sudo apt-key fingerprint 0EBFCD88 sudo add-apt-repository \ "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ \ $(lsb_release -cs) \ stable" sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io sudo service docker status sudo service docker restart sudo usermod -a -G docker jinzhongxu sudo usermod -a -G docker $USER newgrp docker sudo docker run hello-world docker version docker info
离线安装 除了在线安装外,有时候,离线安装也是很常见的。如内网服务器(不方便连接互联网)等。下面介绍在 Debian/Ubuntu 系统中安装的方法。
Debian 系统请访问 Docker 官网 ,并在 Install from a package 一节中,打开网址:https://download.docker.com/linux/debian/dists/ ,然后选择自己服务器版本,进入 pool/stable,选择 amd64, armhf, arm64, s390x 下载 .deb ,注意需要下载 4 个 .deb,分别是 docker-ce, docker-ce-cli, containerd.io, docker-compose-plugin.
1 2 3 4 5 6 7 wget https://download.docker.com/linux/debian/dists/buster/pool/stable/amd64/docker-ce_20.10.9\~3-0\~debian-buster_amd64.deb wget https://download.docker.com/linux/debian/dists/buster/pool/stable/amd64/docker-ce-cli_20.10.9\~3-0\~debian-buster_amd64.deb wget https://download.docker.com/linux/debian/dists/buster/pool/stable/amd64/containerd.io_1.4.3-1_amd64.deb wget https://download.docker.com/linux/debian/dists/buster/pool/stable/amd64/docker-compose-plugin_2.6.0\~debian-buster_amd64.deb sudo dpkg -i *deb
Ubuntu 系统请访问 Docker 官网 ,并在 Install from a package 一节中,打开网址:https://download.docker.com/linux/ubuntu/dists/ ,然后选择自己服务器版本,进入 pool/stable,选择 amd64, armhf, arm64, s390x 下载 .deb ,注意需要下载 4 个 .deb,分别是 docker-ce, docker-ce-cli, containerd.io, docker-compose-plugin.
1 2 3 4 5 6 7 wget https://download.docker.com/linux/ubuntu/dists/bionic/pool/stable/amd64/docker-ce_20.10.9~3-0~ubuntu-bionic_amd64.deb wget https://download.docker.com/linux/ubuntu/dists/bionic/pool/stable/amd64/docker-ce-cli_20.10.9\~3-0\~ubuntu-bionic_amd64.deb wget https://download.docker.com/linux/ubuntu/dists/bionic/pool/stable/amd64/containerd.io_1.4.6-1_amd64.deb wget https://download.docker.com/linux/ubuntu/dists/bionic/pool/stable/amd64/docker-compose-plugin_2.6.0\~ubuntu-bionic_amd64.deb sudo dpkg -i *deb
docker-compose docker compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。下载地址: github docker compose
Compose 使用的三个步骤:
使用 Dockerfile 定义应用程序的环境。
使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
最后,执行 docker-compose up 命令来启动并运行整个应用程序。
docker-compose 安装 1 2 3 4 5 wget https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-linux-x86_64 sudo mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose docker-compose -v
命令行容器自动生成 docker-compose.yml 使用 ghcr.io/red5d/docker-autocompose 来对命令行运行的容器生成 docker-compose.yml 文件,方便下次使用 docker-compose 运行。生成的配置文件包含非常丰富的参数,可以根据个人情况删除、更改。
1 2 3 4 5 docker run --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/red5d/docker-autocompose registry > docker-compose.yml docker run --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/red5d/docker-autocompose redmine-redmine-1 redmine-mariadb-1 > docker-compose.yml
中文显示 在 docker 镜像中运行:
此时,命令行可正常查看中文。在命令行设置,可对当前用户所有终端生效:
1 2 echo 'export LC_ALL="C.UTF-8"' >> ~/.bashrcsource ~/.bashrc
如下设置,可对全局生效,默认 root 用户
1 2 echo 'export LC_ALL="C.UTF-8"' >> /etc/profilesource /etc/profile
建议在创建容器时直接设置语言:
1 docker run -itd --name python -e LANG="C.UTF-8" ubuntu:python /bin/bash
时区 默认运行的容器时区都是 UTC,想要改为 CST,方法如下:
在构建镜像时,设置时区:1 2 ENV TZ=Asia/Shanghai RUN ...
docker-compose 配置文件中,设置时区:1 2 3 4 5 6 7 8 9 environment: - SET_CONTAINER_TIMEZONE=true - CONTAINER_TIMEZONE=Asia/Shanghai environment: - TZ=Asia/Shanghai
在启动容器时,更改时区:1 docker run -e TZ=Asia/Shanghai ...
对运行的容器更改时区:1 2 3 4 5 6 docker cp /usr/share/zoneinfo/PRC colab:/etc/localtime docker restart colab
查看时区:
如果上面方法不管用,那么请直接在容器中安装 tzdata:
1 2 3 4 5 apt update && apt install tzdata -y dpkg-reconfigure tzdata
另一种方法是挂载宿主机的时间配置信息到容器中:
1 2 3 4 docker run -itd --name t2 -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro ubuntu:22.04 bash docker exec t2 date
docker 中使用 GPU 想要在 docker 容器中使用宿主机的 GPU,除了宿主机配置 CUDA 环境 和安装 docker 外,还需要安装如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey | sudo apt-key add - distribution=$(. /etc/os-release;echo $ID$VERSION_ID ) curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution /nvidia-container-runtime.list | sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list sudo apt update sudo apt install nvidia-container-runtime nvidia-container-toolkit -y sudo systemctl stop docker.service sudo systemctl stop docker.socket dockerd --add-runtime=nvidia=/usr/bin/nvidia-container-runtime sudo systemctl restart docker.service
另一种方法:
1 2 3 4 5 6 7 8 sudo apt install curl -y distribution=$(. /etc/os-release;echo $ID$VERSION_ID ) curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/nvidia-docker/$distribution /nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list sudo apt update && sudo apt install -y nvidia-container-toolkit sudo systemctl restart docker
当安装完 nvidia-container-toolkit 后,运行时有时会出现:nvidia-container-cli: ldcache error: open failed: /sbin/ldconfig.real: no such file or directory: unknown.,解决方法:
1 2 ln -s /sbin/ldconfig /sbin/ldconfig.real
最新方法:
1 2 3 4 5 curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \\n && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \\n sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \\n sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update export NVIDIA_CONTAINER_TOOLKIT_VERSION=1.17.8-1\n sudo apt-get install -y \\n nvidia-container-toolkit=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \\n nvidia-container-toolkit-base=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \\n libnvidia-container-tools=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \\n libnvidia-container1=${NVIDIA_CONTAINER_TOOLKIT_VERSION}
创建容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 docker run -itd --name 'ubuntu-xjz-python' -p 9092:80 --gpus=all --shm-size 8G -v /home/jinzhongxu/Documents:/data ubuntu-xjz:v1 /bin/bash docker run -itd --name 'ubuntu-xjz-python' -p 9092:80 --gpus all --shm-size 8G -v /home/jinzhongxu/Documents:/data ubuntu-xjz:v1 /bin/bash docker run -itd --name 'ubuntu-xjz-python' -p 9092:80 --gpus "device=1" --shm-size 8G -v /home/jinzhongxu/Documents:/data ubuntu-xjz:v1 /bin/bash docker run -itd --name 'ubuntu-xjz-python' -p 9092:80 --gpus '"device=1,2"' --shm-size 8G -v /home/jinzhongxu/Documents:/data ubuntu-xjz:v1 /bin/bash docker run -itd --name 'ubuntu-xjz-python' -p 9092:80 --gpus 2 --shm-size 8G -v /home/jinzhongxu/Documents:/data ubuntu-xjz:v1 /bin/bash
测试在 docker 容器中是否可以使用 GPU
1 2 3 4 5 6 7 8 9 10 docker run --gpus all --rm nvidia/cuda:10.2-base nvidia-smi docker run --gpus all --rm nvidia/cuda:10.2-base nvidia-smi -L docker run --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=all --shm-size 8G --rm nvidia/cuda:10.2-base nvidia-smi docker run --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=1,2 --shm-size 8G --rm nvidia/cuda:10.2-base nvidia-smi
打印出 GPU 信息说明验证成功,--gpus 和 -e NVIDIA_VISIBLE_DEVICES 都能实现指定 GPU,但后者 api 接口更容易。更多请访问 NVIDIA 官网教程 .
docker 使用 因 docker hub 在国外,为了加速访问需要给 docker 添加国内镜像,方法如下,打开如下文件,没有则自动创建:
1 sudo vim /etc/docker/daemon.json
添加如下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "registry-mirrors" : [ "https://docker.mirrors.ustc.edu.cn" , "https://registry.docker-cn.com" , "http://hub-mirror.c.163.com" , "https://mirror.baidubce.com" ] , "insecure-registries" : [ "192.168.199.100:5000" ] , "debug" : true , "experimental" : false , "exec-opts" : [ "native.cgroupdriver=cgroupfs" ] , "runtimes" : { "nvidia" : { "path" : "nvidia-container-runtime" , "runtimeArgs" : [ ] } } }
注意:
insecure-registries 为你本地网络私有仓库地址,根据个人情况设置;
runtimes 为容器调用宿主机服务器 GPU 运行时,根据个人情况设置;
对于 cgroup v2,需要增加 "exec-opts": ["native.cgroupdriver=cgroupfs"],,否则,当在宿主机执行 sudo systemct daemon-reload后,将导致 docker 容器中无法再正常访问宿主机的 GPU 资源,造成 cannot open /dev/pts/0: Operation not permitted 的错误。
测试
1 docker pull tensorflow/tensorflow:latest
image Docker 把应用程序及其依赖,打包在 image 文件里面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 docker image pull hello-world docker container run hello-world docker image ls docker image tag (IMAGE ID) (username)/(repository):(tag) docker image build -t (username)/(repository):(tag) . docker image push (username)/(repository):(tag) docker image rm (IMAGE ID) docker image ls -f dangling=true docker image prune docker images -f reference="registr*" docker image --help
container image 文件生成的容器实例,本身也是一个文件,称为容器 (Container) 文件。 也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 docker ps docker container ls docker ps -q docker ps -f ancestor=ubuntu docker ps -f name="myubunt*" docker ps -a -f status=exited docker ps -a docker container ls -all docker stop {CONTAINER ID} docker container stop {CONTAINER ID} docker kill {CONTAINER ID} docker container kill {CONTAINER ID} docker start {CONTAINER ID} docker container start {CONTAINER ID} docker container logs {CONTAINER ID} docker container cp {CONTAINER ID}:{/path/to/file} . docker exec -it {CONTAINER ID} /bin/bash docker exec -it -u root {CONTAINER ID} /bin/bash docker cp {CONTAINER ID}:/opt/bitnami/redmine/config/settings.yml settings.yml docker run -itd --name='centos' -p 8000:80 {IMAGE ID} /bin/bash docker run --network none {IMAGE ID} /bin/bash docker run --name myubuntu -v /tmp:/tmp ubuntu:22.04 docker run --name hello --volumes-from myubuntu ubuntu:22.04 docker container rm {CONTAINER ID} docker commit -a "jinzhongxu" -m "my new cv image" {CONTAINER ID} cv-ubuntu:v1 docker container rm -f ${docker ps -aq} docker container --help
注意:
CONTAINER ID 和 IMAGE ID 只需要输入前几个字符,只要能够唯一识别它们;
docker image 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。image 文件可以看作是容器的模板;
image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image;
一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作;
docker container 设置自启动一般推荐使用 always 参数:–restart=always,更多参数取值如下:
1 2 3 4 5 6 7 8 9 --restart no 默认策略,在容器退出时不重启容器 on-failure 在容器非正常退出时(退出状态非0),才会重启容器 on-failure:3 在容器非正常退出时重启容器,最多重启3次 always 在容器退出时总是重启容器
具体的开启自启和取消自启的命令如下:
1 2 3 4 docker update --restart=always {CONTAINER ID} docker update --restart=no {CONTAINER ID}
制作 docker image 需要用到 Dockerfile 文件。它是一个文本文件,用来配置 image. Docker 根据 该文件生成二进制的 image 文件。
首先,克隆项目
1 2 git clone https://github.com/xxx/demos.git cd demos
在项目的根目录下,新建一个文本文件 .dockerignore, 把要排除的文件或文件夹路径按行写到文件里,参考如下,即说明那些不需要打包进入 image 文件。如果你没有路径要排除,这个文件可以不新建。
1 2 3 .git node_modules npm-debug.log
在项目的根目录下,新建一个文本文件 Dockerfile,
1 2 3 4 5 6 FROM node:11 COPY . /app WORKDIR /app RUN npm install --registry=https://registry.npm.taobao.org EXPOSE 3000 CMD node demos/01.js
说明如下:
1 2 3 4 5 6 FROM node:11:该 image 文件继承官方的 node image,冒号表示标签,这里标签是 11,即 11 版本的 node。 COPY . /app:将当前目录下的所有文件(除了.dockerignore 排除的路径),都拷贝进入 image 文件的/app目录。 WORKDIR /app:指定接下来的工作路径为 /app。 RUN npm install:在/app目录下,运行 npm install 命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。 EXPOSE 3000:将容器 3000 端口暴露出来, 允许外部连接这个端口。 CMD node demos/01.js:表示容器启动后自动执行 node demos/01.js。RUN命令与CMD命令的区别在哪里?简单说,RUN命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;CMD命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个 RUN 命令,但是只能有一个 CMD 命令。注意,指定了 CMD 命令以后,docker container run 命令就不能附加命令了(比如前面的 /bin/bash),否则它会覆盖 CMD 命令。
创建 image 文件. 有了 Dockerfile 文件以后,就可以使用 docker image build命令创建 image 文件了。
1 2 3 docker image build -t demo . docker image build -t demo:0.0.1 .
上面代码中,-t参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是 latest. 最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。
如果运行成功,就可以看到新生成的 image 文件 demo了。
发布 image 的命令参考上面。
常见保留字
FROM: FROME ubuntu:22.04 构建新镜像基于的基础镜像。Dockerfile中第一条必须是 FROM
MAINTAINER: MAINTAINER xjz xjz@gmail.com 镜像维护者姓名和邮箱
RUN: RUN apt install vim -y 容器构建时(docker build)执行的命令,支持两种格式,一种是shell(等同于终端中执行的SHELL命令 RUN apt install vim -y),一种是exec命令 RUN ["./test.php", "dev", "offline"],后两个为参数,等同于 RUN ./test.php dev offline
ENV: ENV MYPATH /usr/local 配置环境变量,指定 export MYPATH=/usr/local
WORKDIR: WORKDIR /usr/local 指定在创建容器后,终端默认登录的工作目录
USER: USER root 指定该镜像以什么用户执行,不指定,默认为 root
VOLUME: VOLUME ["/tmp", "/tmp"] 作用同 -v /tmp:/tmp,指定挂载目录
ADD: ADD java.tar.gz /usr/local/java 把本地压缩包拷贝到镜像,并会自动解压缩tar压缩包。添加时并重命名 ADD docker_boot-0.0.1-SNAPSHOT.jar hello_docker.jar
COPY: COPY java /usr/local/java 把本地文件夹拷贝到镜像,不解压
EXPOSE: EXPOSE 80 启动容器是暴露的端口
CMD: CMD ./start-jupyter.sh or CMD ["./start-jupyter.sh", "run"] 容器启动命令,也支持shell命令和exec命令。指定容器启动后要做的事情。Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换
ENTRYPOINT: ENTRYPOINT ["/bin/ping", "-c", "3"] 也是用来指定一个容器启动时要运行的命令,类似于CMD,但是ENTRYPOINT不会被docker run后面的命令覆盖,如果docker run后面的命令行参数会被当作参数送给ENTRYPOINT指令指定的程序。其实ENTRYPOINT也可以被覆盖:docker run --entrypoint hostname ubuntu:22.04。有些命令运行后就退出了,如 /etc/init.d/ssh start,有些命令会一直运行,如 /bin/bash。如果想要容器启动后一直运行应该选择常驻(一直运行)的命令作为ENTRYPOINT或CMD,如上面的 /bin/bash,或者最后增加上常驻命令。
ENTRYPOINT 和 CMD 搭配使用,ENTRYPOINT 用作执行命令,CMD用作传参数例子:
1 2 3 ENTRYPPOINT ["/bin/ping" , "-c" , "3" ] CMD ["localhost" ]
执行时,可以在docker run后指定新参数覆盖CMD参数:
1 docker run -it myubuntu:v1.0 www.baidu.com
docker network docker 服务默认会创建一个docker0网桥(其上有一个docker0内部接口),该网桥网络的名称为docker0,它在内核层联通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。docker默认指定docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥相互图像。
docker network 分为 bridge, host, none, container 和自建网络。
bridge: 为每一个容器分配、设置IP等,并将容器连接到一个docker0。即虚拟网桥模式,默认为该模式 :docker run ubuntu。网桥docker0创建一对对等虚拟设备接口,一个叫veth(宿主机docker0),一个叫eth0(容器内),两者一一匹配。整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口都叫做veth,在本地主机和容器内创建一个虚拟接口,并让他们彼此联通,这样一对接口叫做veth pari.
host: 容器将不会虚拟出自己的网卡,配置自己的IP等,而是直接使用宿主机的IP和端口与外界通信,不在需要额外进行NAT转换。与宿主机公用一个network namespace,容器不会虚拟出自己的网卡:docker run --network host ubuntu
none: 容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接、IP等,不常用:docker run --network none ubuntu
container: 新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口范围等:docker run --network container:容器名或者容器ID。当指定的共享容器关闭时,当前的容器网络也会断开,只会存在本地回环127.0.0.1。
自建网络:docker network create mybridge,使用自建网络:docker run --network mybridge ubuntu,使用自建网络的好处是除了使用可变的IP互相PING通或连接通外,还可以使用容器名进行PING通或连接上。当容器IP发生改变不会影响使用容器名PING通。建议使用这种方式。
使用bridge模式当容器关闭后重启可能会导致容器IP发生改变,原IP会分配给关闭期间新创建的容器。需要注意。
容器导出和导入镜像 本节演示从拉取基镜像,然后增加个人内容,从容器导出镜像文件(Export a container’s filesystem as a tar archive,不建议这样导出镜像)。把导出的镜像文件拷贝到新的电脑上,然后再导入使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 docker pull ubuntu:latest docker images docker run -itd --name='ubuntu-base' df5de72bdb3b /bin/bash docker ps docker exec -it d090 /bin/bash docker export d090dfda0f04 > myubuntu.tar docker export -o myubuntu.tar d090dfda0f04 docker container export -o myubuntu.tar d090dfda0f04 cat myubuntu.tar | docker import - my/ubuntu:v1docker import myubuntu.tar my/ubuntu:v1 docker image import myubuntu.tar my/ubuntu:v1 docker images docker run -itd --name='ubuntu-personal' 6c5e97787cfc /bin/bash docker ps
上面的方法其实是将容器的文件系统导出为 tar 存档,也可以先把容器打标签成本地镜像,然后用下面的本地镜像导出和导入镜像到其他主机使用。容器打标签成镜像方法如下:
1 2 3 docker commit -a "jinzhongxu" -m "my new image" {CONTAINER ID} {IMAGE NAME}:{TAG}
镜像导出和导入镜像 同容器导出和导入镜像,主要区别是,使用的命令从 export/import 分别变为 save/load.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 docker images docker save -o person.tar e42208a4c3ce docker save > person.tar e42208a4c3ce docker image save -o person.tar e42208a4c3ce docker load -i person.tar docker image load -i person.tar docker images docker tag e42208a4c3ce person/ubuntu:v1 docker images
镜像和容器导入导出的区别
镜像导入是一个复制的过程,容器导入是将当前容器变成一个新的镜像;
docker save 命令保存的是镜像(image),docker export 命令保存的是容器(container);
export 命令导出的 tar 文件略小于 save 命令导出的;
因为 export 导出的是容器,export 导出的文件在 import 导入时,无法保留镜像所有的历史(即每一层 layer 信息),不能进行回滚操作。而 save 是根据镜像来的,所以导入时可以完整保留下每一层 layer 信息;
docker load 不能对导入的镜像重命名,而 docker import 导入可以为镜像指定新名称。
注意:<font color=red> 测试发现 docker 20.10.9 运行 ubuntu22.04 出现异常。</font>问题描述: 外网 docker 20.10.18 基于 ubuntu22.04 安装 基于 miniconda 的 python 环境,并安装支持 GPU 的 torch 和 torchvision,测试能够在 python 中调用服务器 GPU。导出该镜像并刻录到内网,内网部署 docker 20.10.9,加载镜像后能够启动,但 python 无法正常使用,出现 ipython (Original error was: PyCapsule_Import could not import module “datetime” 和 could not start threads 错误)和 numpy (import numpy 出现 OpenBLAS blas_thread_init: pthread_create failed for thread 1 of 999: Operation not permitted OpenBLAS blas_thread_init: RLIMIT_NPROC -1 current, -1 max)。但把镜像拷贝到其他一台能够连接外网的服务器(安装有 docker 20.10.11)上时,能够正常运行。问题排查: 经查发现是 ubuntu21.10 和 fedora35 开始使用glibc2.34甚至更高的版本。在glibc2.34 版本里面,开始使用一个名为 clone3 的系统调用。通常情况下,容器里面所有的系统调用都会被 docker 捕获,然后 docker 决定如何处理它们。如果 docker 中没有为特定系统调用指定策略,则默认的策略会通知容器这边”Permission Denied”。但是,如果 Glibc 收到此错误,它不会回退。它仅在收到响应“此系统调用不可用”时才执行此操作。解决方法:
运行容器的时候,加上这个参数来绕过docker系统调用限制
1 2 3 4 --security-opt seccomp=unconfined docker run -itd --name gputest --gpus all -p 9090:80 -v /workspace:/data --security-opt seccomp=unconfined ubuntu22-gpu:v1 /bin/bash
这能够使得上面的 python 运行但会有很大的问题,一个是你的容器将变得不安全,另一个是这些参数在构建镜像的时候是不可用的。
将 docker 升级到 20.10.11 以上的版本
不要使用基础镜像 ubuntu22.04,而是使用 ubuntu18.04
容器端口映射 有时候在我们运行的容器中有一些服务需要外部网络(docker 容器外)访问,此时就需要在我们从镜像运行容器时指定好本机端口和容器端口的映射,方便在本机直接访问容器中的服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 docker run -itd --name "ubuntu-python" -p 9000:80 {IMAGE ID} docker run -itd --name "ubuntu-python" -p 127.0.0.1:9000:80 {IMAGE ID} docker run -itd --name "ubuntu-python" -p 127.0.0.1::80 {IMAGE ID} docker ps docker port {CONTAINER ID} docker run -itd --name "ubuntu-python" -p 9000:80 -p 9090:8080 {IMAGE ID}
给运行的容器新添加端口映射等其他涉及到非 CPU、内存的操作 对于运行的容器,更改CPU和内存、设置随docker自动开启等都可以使用 docker update 来完成,但是其他涉及到修改容器的端口、挂载点、GPU等需要停止docker服务,然后修改对应容易的配置文件才能完成。关于更新运行容器的CPU和内存等方法可以查看帮助:
目前 docker 没有直接为运行的容器动态增加端口映射的方法。建议从镜像运行容器时考虑清楚哪些端口需要进行映射。如果真的需要为运行的容器再增加新端口映射,可以考虑如下方法:
重新运行容器 最简单的方法就是直接重新再运行容器。如果已经运行的容器个人增加了一些不方便拷贝出来的内容,那么可以先将该容器 commit 成镜像,然后再从新镜像运行容器,增加新端口映射。 容器 commit 镜像的方法:
1 2 3 docker commit -a "jinzhongxu" -m "my new cv image" {CONTAINER ID} cv-ubuntu:v1
修改容器配置文件 如果运行的容器体量太多(如几十G),上面的方法就显得有些不太合适,这里提供一种方法就是修改运行容器的配置文件。
值得一提的是,当对容器的 CPU 和内存修改,可以直接使用命令 docker update --help。除此之外,如容器修改挂载点、修改端口映射等需要修改配置文件。查看配置文件前需要先查看 docker 容器存放的位置:docker info | grep "Root" 和需要修改的容器 ID,使用 docker ps 查看。
修改容器配置文件前,需要先暂时关闭 docker 服务:
1 sudo systemctl stop docker
然后修改配置文件 hostcongfig.json、config.v2.json(如果该文件中有记录)。
查看容器配置信息
1 docker inspect {CONTAINER ID}
进入配置文件目录,修改配置文件
1 2 3 4 5 6 7 cd /var/lib/docker/containersvim hostconfig.json vim config.v2.json
修改成功后,然后重启 docker 服务。
挂载宿主机目录到容器 有时候需要容器能够访问宿主机的某些文件或文件夹,此时,我们可以从镜像创建容器时通过设置挂载点的方式,将宿主机的目录挂载到容器的某个目录,使得容器内部就可以访问宿主机的文件夹。注意,与上面的 cp 命令的区别。
1 2 3 4 5 6 7 8 docker run -itd --name 'ubuntu-test' -v /home/jinzhongxu/Documents:/data ubuntu:latest /bin/bash docker run -itd --name 'ubuntu-test' -v /home/jinzhongxu/Documents:/data:ro ubuntu:latest /bin/bash
有时候,我们需要创建一个新容器,挂载信息同已经创建的一个容器,那么我们可以使用如下方法:
1 2 3 4 docker run -itd --name 'ubuntu-test2' --volumes-from ubuntu-test ubuntu:latest /bin/bash
此时,创建的新容器 ‘ubuntu-test2’ 同旧容器 ‘ubuntu-test’ 具有相同的挂载信息。
容器 SSH 访问宿主机 从容器内部通过SSH访问宿主机能够为容器和宿主机提供更好的交互方式。此时,我们只需要知道宿主机的 docker0 IP,以及宿主机用户名和密码即可。
查看宿主机 docker0 IP 方法是,在宿主机上执行 ifconfig 命令,查看 docker0 对应的 IP,一般为 172.17.0.1;
通过如下方式访问宿主机:
1 2 3 4 ssh jinzhongxu@172.17.0.1
本地私有仓库 docker hub 有时候使用 Docker Hub 这样的公共仓库可能不方便,如内网环境下。此时,用户可以创建一个本地仓库供私人使用。
docker-registry 是官方提供的工具,可以用于构建私有的镜像仓库。本文内容基于 docker-registry v2.x 版本。
安装 docker-registry 如果在能联网的服务器上:
1 2 3 4 5 docker run -d -p 5000:5000 --restart=always -v /opt/data/registry:/var/lib/registry --name registry registry
如果想在内网服务器使用,需要现在能够连接互联网的机器上下载 registry 镜像,然后把该镜像导出,刻录到内网,然后在内网服务器上加载镜像并打标签为 registry:latest(以个人喜好,我这里以此名和标签做演示)。然后使用下面的方式运行。
1 docker run -d --restart=always --name registry -p 5000:5000 -v /opt/data/registry:/var/lib/registry registry:latest
此时,registry 容器在运行,并监控 5000 端口。
在私有仓库上传、搜索、下载镜像 创建好私有仓库之后,就可以使用 docker tag 来标记一个镜像,然后推送它到仓库。例如私有仓库地址为 127.0.0.1:5000,把镜像打标签,以 127.0.0.1:5000 开头:
1 docker tag ubuntu:latest 127.0.0.1:5000/ubuntu18-gpu:v1
提交镜像
1 docker push 127.0.0.1:5000/ubuntu18-gpu:v1
搜索私有仓库中的镜像
1 curl 127.0.0.1:5000/v2/_catalog
结果大概这样
1 {"repositories":["ubuntu18-gpu"]}
从仓库中获取指定镜像的标签
1 curl 127.0.0.1:5000/v2/ubuntu18-gpu/tags/list
结果大概这样
1 {"name":"ubuntu18-gpu","tags":["v1"]}
从私有仓库下载镜像
1 docker pull 127.0.0.1:5000/ubuntu18-gpu:v1
也可以把上面的 127.0.0.1 改成 ipv4 地址
配置非 https 仓库地址 如果你不想使用 127.0.0.1:5000 作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如 192.168.199.100:5000 这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。 这是因为 Docker 默认不允许非 HTTPS 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制,或者查看下一节配置能够通过 HTTPS 访问的私有仓库。Ubuntu 16.04+, Debian 8+, centos 7 对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { "registry-mirrors" : [ "https://docker.mirrors.ustc.edu.cn" , "https://registry.docker-cn.com" , "http://hub-mirror.c.163.com" , "https://mirror.baidubce.com" ] , "insecure-registries" : [ "192.168.199.100:5000" ] , "debug" : true , "experimental" : false , "runtimes" : { "nvidia" : { "path" : "nvidia-container-runtime" , "runtimeArgs" : [ ] } } }
注意:
该文件必须符合 json 规范,否则 Docker 将不能启动
<font color=red>需要重启 docker 才能生效 </font>
上面我增加了容器调用宿主机服务器 GPU 的运行时,根据个人情况添加
systemd 在 Docker 容器中运用 systemctl(即运行 Systemd)通常被视为“反模式”,因为容器旨在运行单个进程。然而,如果必须在容器内运行 systemd(例如为了模拟虚拟机运行复杂的系统服务),可以通过配置特权容器并使用正确的镜像来实现。
并不是所有镜像都能运行 systemctl。需要基于 CentOS、Ubuntu 等发行版并安装了 systemd 的镜像。推荐使用专门的 docker-systemd 镜像,或者在 Dockerfile 中安装 systemd。
核心在于:
使用特权模式 (privileged: true)。
将 /sys/fs/cgroup 挂载到容器。
将容器的初始化进程设置为 /sbin/init 或 /usr/sbin/init。
使用 restart: always 或 unless-stopped 实现容器自动重启。
docker-compose.yaml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 version: '3.8' services: systemd-container: image: ubuntu:22.04.systemd container_name: systemd-server privileged: true volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro command: /usr/sbin/init restart: always
run: docker-compose up -d
ubuntu:22.04.systemd 镜像的生成方法:
先写一个Dockerfile:
1 2 3 4 5 6 7 FROM ubuntu:22.04 RUN apt-get update && apt-get install -y systemd openssh-server && apt-get clean ENV container=docker ENTRYPOINT ["/sbin/init" ]
执行下面命令来生成镜像ubuntu:22.04.systemd:
1 docker build -t ubuntu:22.04.systemd .
其他 指定容器 IP 与宿主机同网段 1 2 3 4 5 6 7 8 9 10 11 sudo modeprobe macvlan sudo lsmod | grep macvlan docker network create -d macvlan --subnet=10.2.28.0/24 --gateway=10.2.28.1 -o parent=eno1 mymacvlan docker run -itd --name lan-desktop --net=mymacvlan --ip=10.2.28.18 ubuntu:18.04 /bin/bash
容器中访问宿主机服务 要求: Docker 版本高于 v20.10 (2020年12月4日更新)
命令行模式下:
1 --add-host=host.docker.internal:host-gateway
Docker Compose 模式下:
1 2 extra_hosts: - "host.docker.internal:host-gateway"
而在 container 内,可请求 host.docker.internal:PORT,来获取宿主机上提供的服务。
容器中安装 opencv-python Ubuntu18.04 容器中安装 opencv-python 需要安装一些依赖包:
1 2 apt update apt install ffmpeg libsm6 libxext6 -y
容器中运行 GUI 界面在宿主机显示 DISPLAY 环境变量格式如下 host:NumA.NumB,其中 host 指 Xserver 所在的主机主机名或者 ip 地址,图形将显示在这一机器上,可以是启动了图形界面的 Linux/Unix 机器,也可以是安装了 Exceed、X-Deep/32 等 Windows 平台运行的 Xserver 的 Windows 机器。如果 Host 为空,则表示 Xserver 运行于本机,并且图形程序(Xclient)使用 unix socket 方式连接到 Xserver,而不是 TCP 方式。使用 TCP方式连接时,NumA 为连接的端口减去 6000 后的值,如果 NumA 为 0,则表示连接到 6000 端口;使用 unix socket 方式连接时则表示连接的 unix socket 的路径,如果为 0,则表示连接到 /tmp/.X11-unix/X0,NumB 则几乎总是0。
以 deeplabcut[gui] 镜像为例,先拉取镜像:
1 docker pull deeplabcut/deeplabcut:2.2.1.1-gui-cuda11.0.3-runtime-ubuntu18.04
然后设置宿主机运行远程连接 X server
启动镜像,注意把本地 DISPLAY 设置上
1 2 3 4 5 docker run -itd --name deeplabcut --gpus=all -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY deeplabcut/deeplabcut:2.2.1.1-gui-cuda11.0.3-runtime-ubuntu18.04 /bin/bash docker run -itd --name deeplabcut --gpus=all -e DISPLAY=10.2.28.12:0.0 deeplabcut/deeplabcut:2.2.1.1-gui-cuda11.0.3-runtime-ubuntu18.04 /bin/bash
进入容器启动 GUI 服务
镜像包依赖问题可能需要把 python 包 wxpython 更改为 4.0.7:
1 pip install wxPython==4.0 .7 .post2
或者直接在容器中安装桌面环境,然后开启远程访问,如 VNC, XRDP 等,远程访问 docker 容器桌面环境,类似于一台正常的远程桌面服务器一样。但是安装桌面环境对于不同的基镜像方法不同,安装的包会有些差别。但是使用起来会更全面。
另外,有时候除了显示容器里GUI程序界面在宿主机,还需要与宿主机程序通信等,可以采用如下方式:
1 2 3 DIR=$(pwd ) xhost + && docker run --gpus all --env NVIDIA_DISABLE_REQUIRE=1 -it --network=host --name bundlesdf --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v /home:/home -v /tmp:/tmp -v /mnt:/mnt -v $DIR :$DIR --ipc=host -e DISPLAY=${DISPLAY} -e GIT_INDEX_FILE nvcr.io/nvidia/bundlesdf:latest bash
–cap-add 参数解决权限问题(无法使用gdb调试、无法date -s修改时间)
–security-opt seccomp=unconfined 选项,它可以取消 Seccomp (Seccomp,即安全计算模式,是 Linux 内核的一部分,用于限制进程可以使用的系统调用。通过禁止或限制对某些系统调用的访问,Seccomp 可以有效减少攻击者能够利用的攻击面。Docker 在默认情况下启用了 Seccomp,并提供了一个默认的配置文件,该文件白名单了大约300个系统调用,其他的则被禁止。这意味着在 Docker 容器中运行的进程只能访问这些已经过滤的系统调用。)的限制,使容器内的进程可以访问所有系统调用。虽然提供了灵活性,但也带来了一些系统风险。禁用 Seccomp 意味着容器内的进程可以访问系统调用,包括那些可能被利用来执行恶意操作的系统调用。
–env NVIDIA_DISABLE_REQUIRE=1 当容器内的 cuda 版本比较宿主机上的驱动版本高时,可能容器里的程序会出现报错。设置改环境变量,让容器内的 cuda 切换为宿主机上的。
–ipc=host 容器共享宿主机的 IPC(inter-process communication) 命名空间,让容器内进程与宿主机的进程进行通信。
容器中运行 pytorch 多 GPU 模型 在容器中运行 pytorch 多 GPU 模型可能会出现如下错误:
ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm). Dataloader中的num_workers设置与docker的shared memory相关问题
这是因为 docker 容器内 shm_size 默认大小 64M 太小导致的问题,有两个解决思路:
在 Dataloader 中将 num_worker 设置为 0,只需在代码中修改比较简单,缺点是训练过程变慢,特别是对较大数据例如视频图像
改变容器中 shared_memory 大小,如下:1 docker run -itd --name mmdet-dlc-multi-gpus --gpus '"device=1,2"' -p 33336:80 --shm-size 8G mmdet-dlc:v1.2 /bin/bash
容器内存和 CPU 限制 有一次在容器中运行一个程序直接爆满宿主机内存,导致服务器无法使用。此时,可以尝试更新容器的内存限制,然后再运行程序,方法如下:
1 2 3 docker update --memory 40g --memory-swap 42g mmdet-dlc-tencent
上面命令设置后,容器就只能使用宿主机内存 40000 MB,但可以使用所有的交换分区。同时,当程序遇到内存不够时会出现 OOM(Out Of Memory)异常退出,解决方法是,在创建容器时,设置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 docker run --cpus="3" --oom-kill-disable --memory="40000m" --memory-swap="50g" --name mmdet-dlc-tencent mmdet-dlc:v2.0 bash docker run --cpuset-cpus="0,1,2" --oom-kill-disable --memory="40000m" --memory-swap="50g" --name mmdet-dlc-tencent mmdet-dlc:v2.0 bash docker run --cpuset-cpus="0-2" --oom-kill-disable --memory="40g" --memory-swap="50g" --name mmdet-dlc-tencent mmdet-dlc:v2.0 bash version: '3.8' services: colab-hub: image: ubuntu:22.04 container_name: colab-huber user: 'root' cpuset: '0-59' mem_limit: '50g' memswap_limit: '52g' oom_kill_disable: true tty : true stdin_open: true entrypoint: ["/bin/bash" , "-c" , "service ssh start && exec /bin/bash" ] expose: - '8000' ports: - '38000:8000' volumes: - '/disk0:/disk0' - '/disk1:/disk1' restart: 'on-failure' environment: - TZ=Asia/Shanghai - LANG=en_US.UTF-8 shm_size: '8g' deploy: resources: reservations: devices: - driver: 'nvidia' count: 'all' capabilities: ['gpu' ] entrypoint: ['/root/start_jupyterhub.sh' ] volumes: colab-hub_data: driver: local networks: default: external: true name: colab apt update && apt upgrade -y unminimize apt install sudo locales man-db tzdata pkg-config iputils-ping zip wget net-tools xz-utils vim htop git rsync gcc g++ make cmake screen curl p7zip-full p7zip-rar openssh-server openssh-client ffmpeg libsm6 libxext6 -y locale-gen en_US en_US.UTF-8 update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 echo 'export LANG=en_US.UTF-8' >> ~/.bashrcstress --cpu 5 docker stats htop
用于测试 docker 中 CPU 分配情况的程序 Python 程序(cpus-limit-test.py):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from multiprocessing import Poolimport timeimport argparsedef t (): parser = argparse.ArgumentParser(description="python argparser" ) parser.add_argument('-c' , "--cpus" , type =int , default=5 ) return parser def loop (i ): while True : pass if __name__ == "__main__" : parser = t() args = parser.parse_args() CPUs = args.cpus p = Pool(CPUs) for i in range (CPUs): p.apply_async(loop, args=(i,)) p.close() p.join()
对容器进行内存现在时有时候会出现错误提示:No swap limit support,此时内存限制是无效的。可以尝试通过如下方法解决:
1 2 3 4 5 6 7 8 9 10 11 sudo vim /etc/default/grub GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1" sudo update-grub sudo shutdown -r now
mac docker 无法启动 mac 中 docker 无法启动,提示:
com.docker.backend cannot start Exit code 101
可尝试如下方法解决:
1 2 pkill Docker killall Docker
然后在重启 docker
mac docker GUI 以 ubuntu:22.04 为例,在容器中安装VNC桌面,并在mac宿主机上访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 docker pull ubuntu:22.04 docker run -itd --name vnc-gui -p 8311:5907 ubuntu:22.04 /bin/bash docker exec -it vnc-gui /bin/bash apt update apt install xorg openbox xserver-xorg-core apt install tigervnc-standalone-server tigervnc-xorg-extension apt install xfce4 xfce4-goodies apt update && sudo apt install locales locale-gen en_US en_US.UTF-8 update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8echo "export LANG=en_US.UTF-8" >> /etc/profileapt install ttf-wqy-zenhei vncpasswd vncserver -localhost no vncserver -list vncserver -kill :1 vncserver -localhost no :7
在Mac上安装tigervnc或其他VNC桌面程序,访问:localhost::8311,输入vncpasswd设置的密码,即可访问。进入后,可以设置默认程序。
安装firefox,建议从firefox官网下载firefox完整程序,手动解压到指定文件夹,设置默认程序时找到解压的firefox文件夹里的firefox可执行文件。
nvidia-smi 在 docker 中看不到进程号 当我们使用 --gpus all 等启动一个想要在 docker 容器中使用 GPU 时,使用命令 nvidia-smi 无法看到当前使用 GPU 的进程 ID,it is related to PID namespaces, the driver is not aware of the PID namespace and thus nvidia-smi in the container doesn’t see any process running. github-nvidia-docker issue . 一种解决方法是启动容器时,增加上一个参数:
或者,使用 python 包 py3nvml,方法如下:
1 2 3 4 5 6 pip install py3nvml py3nvml py3nvml -l 5
同时,py3nvml 作为 python 的一个包,可以在 python 代码中使用来获取 gpu 的实时信息:
1 2 3 import py3nvmlpy3nvml.get_gree_gpus()
迁移 docker 镜像 默认情况下安装的 docker 会自动把镜像文件存储到 /var/lib/docker 目录下,当我们创建的镜像较多较大时,会导致磁盘空间不足等问题,此时,我们可以尝试将镜像存储路径迁移到其他挂载盘:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sudo service docker stop sudo chmod 775 /disk2 sudo mv /var/lib/docker /disk2 vim /etc/docker/daemon.json "data-root" : "/disk2/docker" ,sudo service docker start
docker 磁盘清理 在长时间使用后,docker 镜像会累积,占用大量的磁盘空间。
docker 磁盘分析 使用如下命令可查看 docker 使用空间情况:
1 2 3 docker system df docker system df -v
docker 磁盘清理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 docker system prune docker system prune -a docker image prune docker image prune -a docker container prune docker volume prune docker system prune --help
高版本容器在低版本docker上运行 我在外网ubuntu22.04的docker 20.10.17上生成了一个Ubuntu容器,导入内网ubuntu18.04的docker 20.10.9或更低版本上运行时会出现 error storage folder is not writeable if selinxu is active, you need to add the “:Z” flag to the bind mount、error response from daemon no such host等问题,一种解决方案如下:
docker-compose.yml
1 2 security_opt: - seccomp=unconfined
命令行运行参数
1 docker run --security-opt seccomp=unconfined <image_name> bash
centos8 yum update 如果出现 centos8 中无法 yum update,可使用如下方法:
1 2 sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
centos8 中安装 ssh 1 2 3 yum install openssh-clients openssh-server -y systemctl start sshd systemctl enable sshd
centos8 中安装 nginx 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 yum install gcc wget epel-release -y yum install vim htop make net-tools which -y yum install -y pcre pcre-devel yum install -y zlib zlib-devel wget https://nginx.org/download/nginx-1.22.1.tar.gz tar -xvzf nginx-1.22.1.tar.gz cd nginx-1.22.1./configure --prefix=/usr/local/nginx make -j 4 make install cat > /usr/lib/systemd/system/nginx.service <<-"EOF" [Unit] Description=nginx - web server After=network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/usr/local/nginx/logs/nginx.pid ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/usr/local/nginx/sbin/nginx -s stop ExecQuit=/usr/local/nginx/sbin/nginx -s quit PrivateTmp=true [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl start nginx systemctl enable nginx
no gsettings 当在容器中运行图像界面打开模型交互式界面时出现:
No such file or directory: ‘gsettings’
解决方法:
1 2 apt update apt install libglib2.0-bin
docker pull proxy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 sudo mkdir -p /etc/ systemd/system/ docker.service.d sudo cat > /etc/ systemd/system/ docker.service.d/http-proxy.conf <<-"EOF" [Service] Environment="HTTP_PROXY=http://127.0.0.1:8118" Environment="HTTPS_PROXY=http://127.0.0.1:8118" Environment="NO_PROXY=localhost" EOF sudo systemctl daemon-reload sudo systemctl show --property=Environment docker
注意:如果这里设置了代理,那么push镜像到本地仓库可能会出现问题
Ubuntu desktop 使用纯洁Ubuntu基础镜像,自己按照桌面环境,利用vnc或rdp访问桌面,能够使用宿主机GPU等资源 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 ```bash docker run -it --name ubu22gnome -p 8002:22 -p 8003:3389 -p 8007:5907 ubuntu:22.04 bash ``` ```bash apt update && apt install -y ubuntu-desktop dbus-x11 locales sudo openssh-server openssh-client rm /run/reboot-required*locale-gen en_US en_US.UTF-8 update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 echo 'export LANG=en_US.UTF-8' >> /etc/profileecho 'export LANG=en_US.UTF-8' >> ~/.bashrcadduser jinzhongxu usermod -aG sudo jinzhongxu su - jinzhongxu echo 'export LANG=en_US.UTF-8' >> ~/.bashrccat > /home/jinzhongxu/.xsessionrc <<-"EOF" export GNOME_SHELL_SESSION_MODE=ubuntuexport XDG_SESSION_TYPE=x11export XDG_CURRENT_DESKTOP=ubuntu:GNOMEexport XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdgEOF sudo -i cat > /opt/start-desktop.sh <<-"EOF" sudo service dbus start sudo service ssh start sudo /usr/lib/systemd/systemd-logind EOF chmod +x /opt/start-desktop.sh/bin/bash /opt/start-desktop.sh ``` ```bash apt install -y xorg openbox xserver-xorg-core tigervnc-standalone-server tigervnc-xorg-extension su - jinzhongxu mkdir /home/jinzhongxu/.vncexport PASSWD=123456echo $PASSWD | vncpasswd -f > /home/jinzhongxu/.vnc/passwdchmod 600 /home/jinzhongxu/.vnc/passwdcat > /home/jinzhongxu/.vnc/xstartup <<-"EOF" [ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup [ -r /home/jinzhongxu/.Xresources ] && xrdb /home/jinzhongxu/.Xresources vncconfig -iconic & export DESKTOP_SESSION=/usr/share/xsessions/ubuntu.desktopexport XDG_CURRENT_DESKTOP=ubuntu:GNOMEexport GNOME_SHELL_SESSION_MODE=ubuntuexport XDG_DATA_DIRS=/usr/share/ubuntu:/usr/local/share/:/usr/share/:/var/lib/snapd/desktopdbus-launch --exit-with-session /usr/bin/gnome-session --session=ubuntu EOF chmod +x /home/jinzhongxu/.vnc/xstartuptigervncserver -localhost no :7 tigervncserver -list tigervncserver -kill :7 tigervncserver -localhost no :7 sudo apt install pkg-config iputils-ping zip wget net-tools xz-utils vim htop git rsync gcc g++ make cmake screen curl p7zip-full p7zip-rar openssh-server openssh-client ffmpeg libsm6 libxext6 -y export ALL_PROXY=http://10.2.28.35:8118wget -c -t 0 --no-check-certificate -e use_proxy=yes -e http_proxy=10.2.28.35:8118 -e https_proxy=10.2.28.35:8118 https://github.com/novnc/noVNC/archive/refs/tags/v1.5.0.tar.gz tar -xzvf v1.5.0.tar.gz sudo mv noVNC-1.5.0 /usr/local/noVNC cd /usr/local/noVNC/openssl req -x509 -newkey rsa:2048 -keyout self.pem -out self.pem -days 3650 -nodes /usr/local/noVNC/utils/novnc_proxy --vnc localhost:5907 --listen :3389 sudo -i cat > /opt/start-user-vnc.sh <<-"EOF" tigervncserver -localhost no :7 nohup /usr/local/noVNC/utils/novnc_proxy --vnc localhost:5907 --listen :3389 > /dev/null 2>&1 &EOF sudo chown jinzhongxu:jinzhongxu /opt/start-user-vnc.sh sudo chmod u+x /opt/start-user-vnc.sh cat > /opt/readme.md <<-"EOF" ```bash /bin/bash /opt/start-desktop.sh ``` ```bash /bin/bash /opt/start-user-vnc.sh ``` When creating a container, please map the ports for the following services: - SSH runs on port 22; - VNC runs on port 5907; - noVNC runs on port 3389. ```bash ssh -p hostSSHPort(hostSSHPort:22) jinzhongxu@hostIP ssh -p 2222 jinzhongxu@10.2.28.35 ``` PASSWD is 123456 tigervnc viewer: ```sh hostIP::hostVNCPort(hostVNCPort:5907) 10.2.28.35::8006 ``` PASSWD is 123456 open web browser: ```sh http://hostIP:hostNoVNCPort(hostNoVNCPort:3389)/vnc.html http://10.2.28.35:8008/vnc.html ``` PASSWD is 123456 EOF sudo chmod 777 /opt/readme.md ``` ```bash docker commit -a "jinzhongxu" -m "ssh, vnc, novnc; jinzhongxu; command in /opt" ubu22gnome ubuntu-gnome:22.04.v1 ``` ```bash cat > docker-compose.yaml <<-"EOF" version: '2' services: ub22gnome-gpu: image: ubuntu-gnome:22.04.v1 container_name: ubu22gnome1 hostname: poac-cvdl-pro user: root cpuset: 10-18 mem_limit: 60g memswap_limit: 62g oom_kill_disable: true expose: - '3389' - '5907' - '22' ports: - '8002:22' - 8007:5907 - 9003:3389 volumes: - /usr/local/cuda:/usr/local/cuda restart: on-failure environment: - TZ=Asia/Shanghai - LANG="en_US.UTF-8" shm_size: 40g deploy: resources: reservations: devices: - driver: nvidia device_ids: - '0' capabilities: - gpu entrypoint: - /opt/start-desktop.sh EOF ``` 该方法同样使用于 ubuntu24.04 等
使用Ubuntu原生镜像 这种方式使用宿主机GPU比较麻烦,但是启动的容器是一个完整的Ubuntu系统,能够自己方便管理时间,一些软件需要调整操作系统时间的可以使用这种方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 services: qemu: image: qemux/qemu container_name: qemu-ubuntu22 environment: BOOT: "http://127.0.0.1/ubuntu-22.04.5-desktop-amd64.iso" DISK_SIZE: "128G" RAM_SIZE: "16G" CPU_CORES: "16" GPU: "Y" devices: - /dev/kvm - /dev/net/tun - /dev/dri cap_add: - NET_ADMIN ports: - 8005 :8006 - 2221 :22 volumes: - ./ubuntu:/storage restart: always stop_grace_period: 2m
参考链接
docker国内镜像源
Docker 入门教程
Docker 微服务教程
Docker:docker镜像与容器的导入和导出
runoob.com docker-tutorial
外部访问容器
添加和修改docker容器端口映射的方法
Docker和宿主机之间共享文件
docker 挂载宿主机文件目录
docker容器挂载host宿主机的本地目录,docker容器与宿主机之间互相拷贝文件
Docker Compose
docker使用GPU总结
nathzi1505/install-docker.sh
Docker运行ubuntu22.04出现异常
私有仓库
解决docker警告WARNING: No swap limit support
关于export DISPLAY=:0.0
Docker 网络模型之 macvlan 详解,图解,实验完整
docker容器内访问宿主机host服务