赞
踩
Docker: 码头工人 (搬砖高手)
Life is short. We use Docker.
版本:Ubuntu 16.04 LTS,Docker 19.03.1, build 74b1e89e8a
- # 本节参考 Docker 官方文档:
- # https://docs.docker.com/install/linux/docker-ce/ubuntu/
- # 卸载旧版本
- sudo apt-get remove docker docker-engine docker.io containerd runc
-
- sudo apt-get update
- sudo apt-get install apt-transport-https ca-certificates gnupg-agent software-properties-common
-
- # 添加 Docker 的官方 GPG 密钥
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- # 设置稳定存储库
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
-
- sudo apt-get update
- sudo apt-get install docker-ce docker-ce-cli containerd.io
-
- # 测试
- sudo docker run hello-world
Docker 的 5 个基本部件:Docker Client,Docker Daemon,Docker Image,Docker Container,Docker Hub (Registry)。
- sudo apt-get purge docker-ce
- # 删除相关文件
- sudo rm -rf /var/lib/docker
- docker --version
- sudo docker info
- # 用户访问 Docker daemon,需要管理员权限 sudo,或加入 docker 组
- # Docker 安装完成会建立 docker 组
- cat /etc/group | grep docker
- cat /etc/group | sed -n '/docker/p' | awk -F ":" '{print $1}'
-
- # 加入 docker 组
- sudo usermod -aG docker $USER
- # 重启
- echo -e "USER_PASSWDn" | sudo -S reboot
- # 检查是否已加入 docker 组
- groups | grep docker
- # 详细版本信息
- docker version
- # 列出 image
- docker image ls --all
- docker images
- docker images -a
- # 列出 container
- docker container ls
- docker container ls --all
- docker container ls -aq
- # 搜索
- docker search python
- docker search anaconda
- # 显示运行的容器
- docker ps
- docker ps -a
上图介绍了基本的 docker 命令流,我们从一个小例子开始。
- docker pull busybox
- docker images
- docker run busybox pwd
- docker run busybox echo 'I love Python'
docker pull + docker run 能够让我们迅速、便捷地运行一个 docker image。
格式:docker pull [OPTIONS] NAME[:TAG|@DIGEST]
常用参数
- -a, --all-tags # 下载 repository 中所有 tagged images
- --disable-content-trust # 跳过镜像验证 (默认跳过)
- -q, --quiet # 取消进度显示
格式:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
常用参数:
- -it # -i 交互模式,-t 分配伪 tty
- -P # 随机端口映射
- -p # 指定端口映射,主机端口:容器端口
- --name # 指定容器名称
- -e, --env list # 设置环境变量
- -v, --volume list # 本地文件夹与 container 文件夹绑定
- -w # 容器内的工作目录
- --dns # 设置 DNS 服务器
- -h, --hostname string # 设置容器的 hostname;
- --rm # 自动移除容器
- --env-file list # 从文件读入环境变量
- -d # 后台运行容器
- -m # 设置容器内存上限
- --link list # 链接到其他容器
- # 通过示例展示 docker run 的用法
- # 例一:busybox
- docker pull busybox
- # -it 表示可以交互式地输入命令
- docker run -it busybox sh
-
- # 例二:tensorflow
- docker pull tensorflow/tensorflow
- # --rm 在容器退出时自动清理容器并删除文件系统
- # 默认 python=2.7,tensorflow=1.14.0
- docker run -it --rm tensorflow/tensorflow
- # 退出后运行
- docker container ls --all #不显示 tensorflow,说明 --rm 功能
-
-
- # 定制 python=3.5,tensorflow=1.11.0
- docker pull tensorflow/tensorflow:1.11.0-rc2-py3
-
- # --name 指定 container 名称 [a-zA-Z0-9][a-zA-Z0-9_.-]
- # 命令最后指定 python 解释器,后面可以接 .py 文件
- docker run -it --rm --name tf_11-py_35 tensorflow/tensorflow:1.11.0-rc2-py3 python
-
- # -v 将本地目录映射 container 目录
- # $PWD:/dl 将本地当前目录 $PWD,挂载到 container 的 /dl 目录下
- # -v 命令可以实现数据的完全共享、读写同步
- # 如果想要禁止 container 的写权利,可以 -v $PWD:/dl:ro
- docker run -it --rm --name tf_11-py_35 -v $PWD:/dl tensorflow/tensorflow:1.11.0-rc2-py3 sh # bash 窗口操作
-
- # -p 指定端口映射,可以在本地 http://127.0.0.1:8888 访问 container
- # 本地的 $HOME 目录将被挂载到 /tf 目录下
- docker run -it --rm -v $HOME:/tf -p 8888:8888 tensorflow/tensorflow:nightly-py3-jupyter
-
- # 例三:jupyter
- # 将 container 的 8888 端口映射到本机 127.0.0.1 的 666 端口,
- # http://localhost:666/
- docker run -p 127.0.0.1:666:8888 jupyter/scipy-notebook:17aba6048f44
- # 删除 container
- # 用 CONTAINER ID 或名字
- docker rm c1b9ce7f84d5
- docker rm tf_11-py_35
- docker rm -f $(docker ps -aq)
- # 删除所有状态为 exited 的容器
- docker rm $(docker ps -a -q -f status=exited)
- # 删除镜像 [需要删除镜像的容器]
- # 用 IMAGE ID 或 REPOSITORY:TAG
- docker rmi [OPTIONS] IMAGE [IMAGE...]
- # 启动 container
- docker start d3c0ea01414d
- # 停止 container
- docker stop d3c0ea01414d
- # kill container
- docker kill -s kill d3c0ea01414d
- # 重启 container
- docker restart d3c0ea01414d
- # commit
- docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
首先是 docker 的核心之一,Dockerfile —— 制作 Docker Image 的说明书。
先看三个小例子
例一:ubuntu 16.04 LTS (xenial) 官方 Dockerfile
- FROM ubuntu:xenial
-
- RUN apt-get update && apt-get install -y --no-install-recommends
- ca-certificates
- curl
- netbase
- wget
- && rm -rf /var/lib/apt/lists/*
-
- RUN set -ex;
- if ! command -v gpg > /dev/null; then
- apt-get update;
- apt-get install -y --no-install-recommends
- gnupg
- dirmngr
- ;
- rm -rf /var/lib/apt/lists/*;
- fi
例二:jupyter minimal-notebook 官方 Dockerfile
- # Copyright (c) Jupyter Development Team.
- # Distributed under the terms of the Modified BSD License.
- ARG BASE_CONTAINER=jupyter/base-notebook
- FROM $BASE_CONTAINER
-
- LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>"
-
- USER root
-
- # Install all OS dependencies for fully functional notebook server
- RUN apt-get update && apt-get install -yq --no-install-recommends
- build-essential
- emacs
- git
- inkscape
- jed
- libsm6
- libxext-dev
- libxrender1
- lmodern
- netcat
- pandoc
- python-dev
- texlive-fonts-extra
- texlive-fonts-recommended
- texlive-generic-recommended
- texlive-latex-base
- texlive-latex-extra
- texlive-xetex
- tzdata
- unzip
- nano
- && rm -rf /var/lib/apt/lists/*
-
- # Switch back to jovyan to avoid accidental container runs as root
- USER $NB_UID
例三:nvidia/cuda 的 cuda9.0+cudnn7.6 官方 Dockerfile
- ARG IMAGE_NAME
- FROM ${IMAGE_NAME}:9.0-devel-ubuntu16.04
- LABEL maintainer "NVIDIA CORPORATION <cudatools@nvidia.com>"
-
- ENV CUDNN_VERSION 7.6.3.30
- LABEL com.nvidia.cudnn.version="${CUDNN_VERSION}"
-
- RUN apt-get update && apt-get install -y --no-install-recommends
- libcudnn7=$CUDNN_VERSION-1+cuda9.0
- libcudnn7-dev=$CUDNN_VERSION-1+cuda9.0
- &&
- apt-mark hold libcudnn7 &&
- rm -rf /var/lib/apt/lists/*
Dockerfile 指令解析
- # FROM 指定基础的 Docker Image,可以来自官方远程仓库,也可位于本地仓库
- # 没有指定镜像标签,则默认使用 latest 标签
- FROM ImageName
-
- # 创建镜像的用户
- MAINTAINER UserName
- MAINTAINER "Jupyter Project <jupyter@googlegroups.com>"
- LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>"
-
- # 每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像,
- # 后续的 RUN 都以之前 RUN 提交的镜像为基础,
- # 镜像是分层的,可以通过一个镜像的任何一个历史提交点来创建。
- RUN command1 && command2 && ...
-
- # ENV 设置环境变量,后续 RUN 指令使用,并在容器运行时保留
- ENV KEY value # 只能设置一个变量
- ENV KEY=value # 允许一次设置多个变量
-
- # ARG 定义了一个变量,能让用户可以在构建期间使用 docker build 命令和其参数 --build-arg 对这个变量赋值
- # 例三中,可以用如下命令传入参数:
- # docker build --build-arg IMAGE_NAME=nvidia/cuda Dockerfile
- ARG <name>[=<default value>]
-
-
- # COPY,ADD 将宿主目录下 [或者远程文件 URLS] 的文件拷贝进镜像
- # ADD 可自动处理 URL 和解压 tar 包,COPY 不能指定远程文件 URLS
- COPY src dest
- ADD src dest
-
- # WORKDIR 指定在创建 container 后,终端默认登录的 container 的工作目录,未指定则在根目录
- WORKDIR
-
- # CMD 指定一个容器启动时要运行的命令
- # DockerFile 中可以有多个 CMD 指令,但是只有最后一个生效
- # 如果用户启动容器时指定了运行的命令,则会覆盖掉 CMD 指定的命令。
- # 如:docker run -it --rm --name tf_11-py_35 -v $PWD:/dl tensorflow/tensorflow:1.11.0-rc2-py3 sh
- CMD
- CMD echo $HOME
- CMD [ "sh", "-c", "echo $HOME" ]
-
- # ENTRYPOINT 配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
- # 每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个生效。
- ENTRYPOINT
-
- # 指定对外的端口号
- # 默认为 8888,对于 docker run 指令中的 -p 参数产生影响
- EXPOSE
-
- # 容器数据卷,用于数据保存和持久化工作
- VOLUME
- VOLUME /docker_data
格式:
- docker build [OPTIONS] PATH | URL | -
- docker image build [OPTIONS] PATH | URL | -
常用参数:
- -f, --file string # Name of the Dockerfile (Default is 'PATH/Dockerfile')
- --build-arg list # Set build-time variables
- --compress # Compress the build context using gzip
- -t, --tag list # Name and optionally a tag in the 'name:tag' format
- --rm # Remove intermediate containers after a successful build (default true)
下面通过两个例子展示编写 Dockerfile 及创建镜像的过程。
python==3.6,numpy==1.14.2,tensorflow==1.12.0
Dockerfile
- FROM python:3.6
- WORKDIR /tensorflow
- COPY requirements.txt ./
- RUN pip install --no-cache-dir -r requirements.txt
- COPY . .
- CMD [ "python", "./tf.py" ] # tf.py 是用户自己的 .py 文件
requirements.txt
- numpy==1.14.2
- tensorflow==1.12.0
创建镜像
- # build image
- docker image build -t py36tf:0.0.1 .
创建过程如下,注意 docker 镜像是分层创建的,每次执行命令都会产生新的镜像
- Step 1/6 : FROM python:3.6 #下载 python:3.6 的 image
- ---> 1c515a624542
- Step 2/6 : WORKDIR /home/lizhongding/codeLinux/dp
- ---> Running in 4c77d0b86f09 # 设置工作目录,在容器 4c77d0b86f09 中运行
- Removing intermediate container 4c77d0b86f09 # 移除中间 container 4c77d0b86f09
- ---> 708c4ca1c9dd
- Step 3/6 : COPY requirements.txt ./ # 拷贝 requirements.txt,到镜像的根目录下
- ---> ee1bde24d6b1
- Step 4/6 : RUN pip install --no-cache-dir -r requirements.txt # 安装 numpy==1.14.2,tensorflow==1.12.0 及相关依赖
- ---> Running in ed988a6febfe
- Removing intermediate container ed988a6febfe
- ---> 22348b6a3d9f
- Step 5/6 : COPY . . # 将当前目录的文件拷贝进镜像的当前目录
- ---> 0117e5a5ae26
- Step 6/6 : CMD python tf.py # 执行命令 python tf.py
- ---> Running in 4edf63c674f8
- Removing intermediate container 4edf63c674f8
- ---> 1fde2f3a630f
- Successfully built 1fde2f3a630f # 建立镜像 1fde2f3a630f
- Successfully tagged py36tf:0.0.1 # REPOSITORY:TAG = py36tf:0.0.1
上传镜像
- # 在 hub.docker.com 上注册帐号
- docker login
-
- # 建立本地映像与存储库的关联
- docker image tag ImageName UserName/repository[:tag] # 默认 tag 为 latest
- docker image tag py36tf:0.0.1 lizhongding/py36tf:0.0.1
- docker image push lizhongding/py36tf:0.0.1
- # 成功后,可在 hub.docker.com 上查看 image
- # 相似依赖的镜像,再上传时会尽量利用已有镜像
- docker image tag py36tf:0.0.2 lizhongding/py36tf:0.0.2
- docker image push lizhongding/py36tf:0.0.2
下载最新版的 ananconda3,利用 conda 安装以下 package:
Dockfile 构建如下。[参考项目:okwrtdsh/anaconda3]
- FROM nvidia/cuda:9.0-cudnn7-devel
-
- USER root
- ENV DEBIAN_FRONTEND=noninteractive
- LANG=C.UTF-8
- LC_ALL=C.UTF-8
- PATH=/opt/conda/bin:$PATH
- NOTEBOOK_DIR=/src/notebooks
- NOTEBOOK_IP=0.0.0.0
- NOTEBOOK_PORT=8888
-
- RUN apt-get update -qq
- && apt-get upgrade -y
- && apt-get install --no-install-recommends -y
- curl grep sed dpkg wget bzip2 ca-certificates
- libglib2.0-0 libxext6 libsm6 libxrender1
- git mercurial subversion
- libgtk2.0-0
- # 最新版 annaconda3 安装
- && echo 'export PATH=/opt/conda/bin:$PATH' > /etc/profile.d/conda.sh
- && ANACONDA_INSTALL_SCRIPT='Anaconda3-2019.03-Linux-x86_64.sh'
- && wget --quiet https://repo.continuum.io/archive/$ANACONDA_INSTALL_SCRIPT -O ~/anaconda.sh
- && /bin/bash ~/anaconda.sh -b -p /opt/conda
- && rm ~/anaconda.sh
- && apt-get clean
- && rm -rf /var/lib/apt/lists/*
-
- RUN conda config --add channels conda-forge
- && conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
- && conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
- && conda install -y --quiet
- jupyter
- Pillow
- matplotlib
- pyyaml
- python-lmdb
- scikit-learn
- tqdm
- tensorflow-gpu=1.11.0
- cudatoolkit=9.0
- python=3.6
- && conda install -c menpo opencv3
- && conda clean -tipsy
-
- # 安装 tini
- ENV TINI_VERSION=v0.18.0
- ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/bin/tini
- RUN chmod +x /usr/bin/tini
- ENTRYPOINT [ "/usr/bin/tini", "--" ]
-
- CMD jupyter notebook
- --notebook-dir=${NOTEBOOK_DIR}
- --ip=${NOTEBOOK_IP}
- --port=${NOTEBOOK_PORT}
- --NotebookApp.token=''
- --no-browser
- --allow-root
上传镜像
- docker image build -t :0.0.1 .
- docker login
- docker image tag gan:0.0.1 lizhongding/gan:0.0.1
- docker image push lizhongding/gan:0.0.1
docker 镜像可以不必在 docker hub 存取,也可本地存取。
格式:docker save [OPTIONS] IMAGE [IMAGE...]
参数:--output , -o
示例:
- docker save busybox > busybox.tar
- ls -sh busybox.tar
- # 2.7M busybox.tar
-
- docker save --output busybox.tar busybox
- ls -sh busybox.tar
- # 2.7M busybox.tar
-
- # 用 gzip 压缩
- docker save gan:0.0.1 | gzip > gan:0.0.1.tar.gz
格式:docker load [OPTIONS]
参数:--input , -i
- docker load < busybox.tar.gz
- docker load --input fedora.tar
- docker images
当镜像中包含 gpu 的操作时,需要 nvidia-docker 来 run 镜像。
- # 卸载 nvidia-docker 1.0
- docker volume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
- sudo apt-get purge nvidia-docker
-
- # 安装依赖
- 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-get update && sudo apt-get install -y nvidia-container-toolkit
- sudo systemctl restart docker
-
- # 用 nvidia-smi 测试镜像
- docker run --gpus all nvidia/cuda:9.0-base nvidia-smi
-
- # 安装 nvidia-docker2
- sudo apt-get install nvidia-docker2
- sudo pkill -SIGHUP dockerd
-
- # 用 tensorflow-gpu 进行测试
- # 注意 tensorflow/tensorflow 镜像中支持的 cuda 版本要与本机 cuda 版本匹配
- # 最新版要求 cuda>=10.0
- nvidia-docker run -it --rm --name tf_gpu tensorflow/tensorflow:1.11.0-devel-gpu-py3
- python -c "import tensorflow as tf; tf.enable_eager_execution(); print(tf.reduce_sum(tf.random_normal([1000, 1000])))"
在正在运行的容器中运行命令
格式:docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
参数:
- --detach, -d # 分离模式:在后台运行命令
- --detach-keys # 覆盖用于分离容器的键序列
- --env, -e # 设置环境变量
- --interactive, -i # 即使没有连接,也要保持STDIN打开
- --privileged # 为命令提供扩展权限
- --tty, -t # 分配伪TTY
- --user, -u # 用户名或UID(格式:<name | uid> [:<group | gid>])
- --workdir, -w # 容器内的工作目录
示例:
- docker restart tf_gpu
- # 访问 container
- docker exec -it tf_gpu bash
- docker exec -it tf_gpu python
格式:docker inspect [OPTIONS] NAME|ID [NAME|ID...]
- docker inspect tf_gpu
- docker inspect 157efda75cac
- # 打印 json 字符串,所有相关信息都可以查看
将本地标准输入,输出和错误流附加到正在运行的容器。
简单说,就是可以在命令行进入并操作容器。
格式:docker attach [OPTIONS] CONTAINER
- docker attach tf_gpu
- docker attach f8268dbfd125
namespace 是实现隔离的机制。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。