explorer

万丈高楼平地起,勿在浮沙筑高台

0%

[What]docker -> 操作速查

笔记:

  1. Docker - 从入门到实践
  2. docker document
  3. 《第一本 Docker 书》

基本概念

核心组件

Docker 的核心组件:

  1. Docker 客户端和服务器
  2. Docker 镜像(Image)
  3. Docker 仓库(Repository)
  4. Docker 容器(Container)

客户端和服务器

Docker 是一个 C/S 架构的程序,那么就是说:

  • 由服务端来完成客户端的请求并返回结果
  • 客户端既可以和服务端在同一台主机,也可以远程访问其他主机上的 Docker 服务端

镜像

指的就是运行的文件系统环境包(就是一个独立的根文件系统),里面包含了必要的库,一般镜像是存储于远程库中的,供大家分享。

容器

将远程镜像抓取下来, 然后创建的实体就是容器。这是用户的实际运行环境,对容器的更改,可以反映到镜像中。

镜像以增量的方式保存,以前的更改可以为不同时期的状态创建一个 tag,这点运行机制和 git 类似。

当容器中指定的应用终结时,容器也自动终止。

仓库(Registry)

用于存储镜像的位置,类似于 github。Docker 公司运营着 Docker Hub,在上面可以创建自己的公开或私有镜像。

技术组件

  • 文件系统隔离:每个容器都有自己的根文件系统
  • 进程隔离:每个容器运行在自己的进程环境中
  • 网络隔离:容器间的虚拟网络接口和 IP 地址都是分开的
  • 资源隔离和分组:使用 cgroups 将 CPU 、内存、IO 资源按比例分配给每个 Docker 容器
  • 写时复制:基于 COW 可以很好的节约文件系统的占用空间
  • 日志:用于分析故障
  • 交互式 shell:用户可以通过 shell 与 Docker 容器交互

在 ubuntu 18.04 安装

卸载以前的版本

sudo apt remove docker docker-engine docker.io

安装

# 安装基础环境
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common

#添加国内的镜像
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
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

启动及配置

关于国内镜像加速,参考此处。

#启动
sudo systemctl enable docker
sudo systemctl start docker
#建立用户组,(默认root 和 docker组 的用户才可以访问 docker 引擎的 socket
sudo groupadd docker
#将当前用户加入组
sudo usermod -aG docker ${USER}
#验证是否加入成功
groups ${USER}
#重启系统
sudo reboot
#如果抓取镜像很慢,可以从国内云获得的加速器地址加入配置, 然后重新启动
#sudo vim /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ]
}
# 设置完镜像后需要再次重启
sudo systemctl enable docker
sudo systemctl start docker

#验证安装是否成功
docker run hello-world
#查看 docker 信息
docker info

Docker 服务端通过监听 /var/run/docker.sock 这个 Unix socket 文件来获取客户端的 Docker 请求。

使用

镜像

获取镜像

镜像存储于 docker hub 中, 类似于 github.

获取镜像的格式为:

# [docker registry address] 指的是 <域名/IP>[:端口号],如果不填那就默认是 docker hub 地址
# [repository name] 指的是 <用户名>/<镜像名>,如果在 docker hub 地址上不填, 那用户名就默认是 library
# <tag> 则是对应镜像所建立的标签, 和 git 中的 tag 类似
# 比如 docker pull ubuntu:18.04 就是获取 docker hub 下的 library/ubuntu:18.04
docker pull [option] [docker registry address]<repository name>:[tag]

通过镜像启动容器

#启动镜像里面的bash
# -it : 启动一个交互式(i)的终端(t)
# -rm : 在容器退出后, 删除其所占有的空间
# ubuntu:18.04 bash : 以 ubuntu:18.04 为基础,并启动里面的 bash
docker run -it --rm ubuntu:18.04 bash

查看镜像

  • docker images / docker image ls : 查看已经下载下来的镜像
  • docker system df : 查看镜像、容器、数据卷所占用的内存空间
  • docker images -a : 在显示所有镜像的同时也显示中间层镜像(多个镜像共用的层)
  • docker images <image name> : 根据仓库命列出镜像
  • docker images <image name>:<tag> : 列出某个镜像的特定标签
  • docker images -f since/before=<image name>:<tag> : 在某个镜像之后(之前)建立的镜像
  • docker image prune : 删除所有的虚悬镜像(dangling image).
    • 虚悬镜像就是以前的旧的镜像,已经被新的镜像所替代了,可以删除

定制镜像

  • 使用 commit (不推荐)

    在容器中, 修改的文件系统都会被记录于容器存储层了,使用 docker commit 命令将这些变化保存为一个镜像.

    docker commit [option] [container id or name] [<repository name>[:<tag>]]
    
    #一般的应用如下
    docker commit --author "author information" --message "commit message" <container name>\
     <repository name>:<new tag name>
    • docker history <repository name>:<tag> : 显示修改历史
  • 使用 Dockerfile

    Dockerfile 就是又一系列的脚本组成, 表示了从最开始到现在镜像所构建的每一层的命令. 这样对于以后的维护工作就透明简洁了.

    • 使用习惯 : 为Dockerfile 新建一个空目录, 然后编辑此文件, 当有软件包需要编译时, 将软件包拷贝至当前目录, 然后在 dockerfile 中使用 ADD 命令再统一拷贝到一个文件夹中.
      • 简单点理解, Dockerfile 有点类似于 makefile.

    当编辑好 Dockerfile 后, 在 Dockerfile 文件所在目录处执行命令:

    # context path : 上下文路径
    # docker 是基于 C/S 架构的运行机制, 通常我们操作的都是客户端, 然后与服务器进行消息通信.
    # 在编译过程中, 需要给 build 命令指定一个上下文路径, build命令会将此路径下的所有文件都压缩拷贝至服务器
    # 所以, 在需要安装一些软件包的时候, 需要主动将软件包拷贝到上下文目录下(一般是当前目录), 然后所有操作都在此目录
    # 下完成
    docker build [options] -t <image name>:<tag name> <context path>
    
    #也可以使用简易命令
    docker image build
    • 指令
      • FROM : 指定基础镜像, 代表后面命令的修改都是在此镜像的基础之上完成的. 必须是 Dockerfile 中的第一条命令.
        • 当使用 FROM scratch 时, 代表不基于任何镜像构建,很多时候就是直接将可执行文件复制进镜像即可.
      FROM nginx
      ....
      • RUN : 执行命令行的命令, 可以执行 shell 脚本的命令
        • 每执行RUN都会启动一个容器新建立一层镜像, 也就是说各个RUN命令之间没有联系! 可以将多个命令集合在一个RUN中减少层数
      FROM debian:jessie 
      RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html 
      RUN apt-get update
      RUN apt-get install -y gcc libc6-dev make 
      RUN make -C /usr/src/redis 
      RUN make -C /usr/src/redis install 
      ....
      # 执行命令的中间文件, 应该删除以保证包尽量的小
      FROM debian:jessie
      
      RUN buildDeps='gcc libc6-dev make' \
          && apt-get update \
          && apt-get install -y $buildDeps \
          && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
          && mkdir -p /usr/src/redis \
          && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
          && make -C /usr/src/redis \
          && make -C /usr/src/redis install \
          && rm -rf /var/lib/apt/lists/* \
          && rm redis.tar.gz \
          && rm -r /usr/src/redis \
      # 清理 apt 缓存
          && apt-get purge -y --auto-remove $buildDeps
      • COPY : 在服务器端, 相对于上下文环境 复制文件
        • COPY <source> <destination>
      • ADD : 高级复制
        • ADD 的源路径可以是 URL 或 压缩(gzip, bzip2, xz)文件, 这样可以自动下载以及解压缩到目的地址去
      • CMD : 容器启动命令, 用于指定默认的容器主进程的启动命令. 在实际使用时, 启动容器后面跟着的命令就会替换 CMD 的默认值, 否则就运行CMD指定的命令
        • 需要注意的是, 在容器中不能启动后台命令.因为一个容器就是一个进程, 而不是虚拟机.
      • ENTRYPOINT : 入口点, 也是用于指定容器启动程序及参数
        • 在实际使用时, 可以在启动容器名后面跟参数, 这个参数就会作为 ENTRYPOINT 的参数.
      FROM ubuntu:16.04
      RUN apt-get update \
          && apt-get install -y curl \
          && rm -rf /var/lib/apt/lists/*
      ENTRYPOINT ["curl", "-s", "http://ip.cn"]
      
      #当外部使用 docker run myip -i 时, 实际 -i 就作为参数传递给了 ENTRYPOINT ,
      # 也就是说,容器在启动后会运行命令为: curl -s http://ip.cn -i
      • ENV 设置环境变量
        • ENV <key> <value> / ENV <key1>=<value1> <key2>=<value2>
      ENV NODE_VERSION 7.2.0
      
      RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
        && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
        && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
        && grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
        && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
        && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
        && ln -s /usr/local/bin/node /usr/local/bin/nodejs
      • ARG : 构建参数, 这些参数都是在构建命令的时候所使用的, 该默认值可以在构建命令 docker build 中使用 --build-arg <argument name>=<value> 来覆盖.
        • ARG <argument name>[=<default value>]
      • VOLUME : 定义匿名卷, 为了避免向容器存储层写入大量数据,需要将这些数据保存在卷中.
        • VOLUE ["<path1>", "<path2>"…] / VOLUE <path>
      # /data 目录就会在运行时自动挂载为匿名卷, 任何向 /data 中写入的信息都不会记录进容器存储层.
      VOLUME /data
      • EXPOSE : 声明端口, 声明运行时容器提供服务的端口, 但并不一定会使用此端口
        • EXPOER <port1> [<port2> …]
        • 在运行容器时使用 -p <宿主端口>:<容器端口> 就会将容器对应的端口服务公开给外界访问
      • WORKDIR 指定工作目录, 此命令可以影响以后的层.
        • WORKDIR <path>
      • USER 指定当前用户, 此命令可以影响以后的层.
        • USER <user name>
      • HEALTHCHECK: 健康检查, 检查容器是否运行正常
        • HEALTHCHECK [option] CMD <command> : 设置检查容器健康状况的命令
        • HEALTHCHECK NONE : 如果基础镜像有健康检查指令, 此命令用于屏蔽掉健康检查指令.
      # HEALTHCHECK 支持下列选项
      --interval=<间隔> : 两次健康检查的间隔
      --timeout=<时长> : 如果超过时间无响应, 则本次检查被视为失败,默认30秒
      --retries=<次数> : 当连续几次失败后, 容器就被视为 unhealthy, 默认3次
      
      FROM nginx
      RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
      #每5秒检查一次, 超过3秒就视为失败, 使用命令 curl 来检查
      HEALTHCHECK --interval=5s --timeout=3s \
        CMD curl -fs http://localhost/ || exit 1

      如果容器为 unhealthy , 可以使用 docker inspect 来查看.

      • ONBUILD : OUTBUILD 后面跟其他指定, 这些指令在当前镜像构建时并不会被执行. 只有当以当前镜像为基础镜像,区构建下一级镜像的时候才会被执行.
        • ONBUILD <command>
  • 使用压缩包导入

    通过压缩包导入的镜像将会作为第一层镜像.

    • docker import [option] <file>|<URL>| [<repository>[:<tag>]]
    docker import \
        http://download.openvz.org/template/precreated/ubuntu-14.04-x86_64-minimal.tar.gz \
        openvz/ubuntu:14.04
    Downloading from http://download.openvz.org/template/precreated/ubuntu-14.04-x86_64-minimal.tar.gz
    sha256:f477a6e18e989839d25223f301ef738b69621c4877600ae6467c4e5289822a79B/78.42 MB

删除镜像

删除镜像使用如下指令

  • docker rmi [option] <image1> [<image2> …]

对应的删除容器则使用

  • docker rm [option] <container>

注意: 删除命令不一定会真的删除镜像,有以下几种情况:

  1. 如果有多个标签指向了同一个镜像, 那么就只是删除标签.
  2. 如果有多个镜像以此层为基础, 那么需要其他层删除后才能删除此层
  3. 如果有与此镜像对应的容器存在, 那么需要先删除容器

容器

容器是独立运行的一个或一组应用, 以及它们的运行态环境. 虚拟机可以理解为模拟运行的一套操作系统和基于系统的应用.

启动

首次启动

  • docker run [option] <image name>:<tag> [command] 或者 docker container run [option] <image name>:<tag> [command]
    • docker run -t -i ubuntu:18.04 /bin/bash : 启动一个容器并打开其交互终端

执行这些命令后, docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定的镜像, 不存在就从公有库下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统, 并在只读的镜像层外面挂载一层可读可写层
  • 从宿主主机配置的网桥中桥接一个虚拟接口到容器中去
  • 从地址池配置一个 ip 地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被终止

启动已终止的容器

  • docker start <container name> 或者 docker container start

后台运行

在运行命令中加入 -d 参数, 容器就不会输出结果打印到宿主机上面. 使用命令 docker logs <container name> / docker container logs <container name> 来查看信息输出.

通过命令 docker ps / docker container ls 查看正在运行的容器.

终止和重启容器

  • docker stop <container name>: 终止一个运行中的容器.
  • docker ps -a : 查看所有的容器信息
  • docker restart <container name>/ docker container restart <container name> : 重启一个容器

进入容器

  • docker attach <container name> : 进入容器
    • 当终端退出后,容器会退出
  • docker exec -it <container name> bash : 分配终端连接容器
    • 当终端退出后,容器不会退出

导出和导入

  • docker export <container name> > <filename.tar> / docker container export <container name> > <filename.tar>: 导出容器快照
  • docker import <URL/file> / docker image import <URL/file>: 将容器快照导入

删除

  • docker rm <container name> : 删除一个处于终止状态的容器, 加入 -f 则会停止一个容器并删除, docker rm $(docker ps -a -q) 删除所有处于终止状态的容器
  • docker container rm <container name> / docker container prune

仓库

docker hub

  • docker login : 登录仓库
  • docker logout : 退出仓库
  • docker search <image name>: 查找镜像
  • docker pull / push <image name> : 抓取或推送到库

私有仓库

创建私有仓库:

  • docker run -d -p 5000:5000 –restart=always –name registry registry : 使用官方的 registry 镜像来启动私有仓库
    • 私有仓库默认被创建在 /var/lib/registry 目录下

将本机镜像标记:

  • docker tag IMAGE:[TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
    • 比如 docker tag ubuntu:latest 127.0.0.1:5000/ubuntu:latest 将 ubuntu:latest 标记到私有仓库

上传镜像到私有仓库:

  • docker push 127.0.0.1:5000/ubuntu:latest

下载镜像:

  • docker push 127.0.0.1:5000/ubuntu:latest

数据管理

数据卷

  • 数据卷可以一个或多个容器使用
  • 对数据卷的修改会立即生效
  • 对数据卷的更新不会影响镜像
  • 数据卷会一直存在, 即是容器被删除.
  • docker volume create <volume name> : 创建一个数据卷
  • docker volume ls : 查看数据卷
  • docker run -d -P –name web –mount source=my-vol,target=/webapp training/webapp python app.py
    • 创建一个名为 web 的容器,讲数据卷 my-vol 挂载到容器的 /webapp 目录
  • docker volume rm <volume name> : 删除一个数据卷
  • docker volume prune : 删除未被挂载使用的数据卷
  • docker inspect web : 查看 web 信息

主机目录

  • docker run -d -P –name web –mount type=bind,source=/src/webapp,target=/opt/webapp taraining/webapp python app.py
    • 挂载 本地 目录 /src/webapp 到容器的 /opt/webapp 目录中
  • docker run –rm -it –mount type=bind,source=${HOME}/.bash_history,target=/root/.bash_history ubuntu:18.04 bash
    • 挂载主机文件 .bash_history 到容器的 .bash_history

网络访问

外部访问

使用 -P / -p 来指定主机到容器的端口映射(P -> 随机映射 p -> 指定映射), 可以通过 docker ps 来查看实际映射情况

  • docker run -d -p 5000:5000 training/webapp python app.py : 本地5000端口映射到容器的5000端口
  • docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py : 映射到指定地址的指定端口
  • docker run -d -p 127.0.0.1::5000 training/webapp python app.py : 映射到指定地址的任意端口
  • docker port <container name> [port] : 查看映射端口的配置

容器互联

  • docker network create -d bridge <net name> : 新建一个 docker 网络
  • docker run -it –rm –name <container name> –network <net name> <image> <command> : 运行一个容器并连接到网络

定制镜像

定制的原理

由于 Docker 是一个 C/S 架构,所以其构建过程为:

  1. 客户端指定构建上下文路径
  2. 客户端讲此上下文路径中的文件打包,发送给服务端
  3. 服务端获取到压缩包以后,开始构建

Docker 通过 Dockerfile 来指定构建镜像的规则,Dockerfile 包含的就是当前这一新镜像的构建脚本。

基于以上过程,一般习惯是:

  1. 新建一个空目录,编写 Dockerfile
  2. 如果 Dockerfile 包含额外的文件需要构建的话, 将那些文件拷贝到此目录
  3. 运行构建命令,指定此构建上下文路径

如果当前目录有些文件不希望被打包传输的话,需要编写一个 .dockerignore 文件来过滤这些文件。

  • 和 git 的 .gitignore 一样

Docker 使用 docker build [opt] <path> 来调取 Dockerfile 进行镜像构建。

  • 其中 path 就代表构建上下文路径,一般为点(.),因为我们一般在 Dockerfile 的所在目录运行此命令

基本命令

Dockerfile 具有常用命令:

FROM : 指定基础镜像

FROM 是 Dockerfile 中的第一条指令,用于指定基础镜像,基于此镜像进行构建。

如果不需要基于任何镜像,那么 FROM 后跟 scratch

FROM scratch

RUN : 执行命令

RUN 命令有两种格式:

  • shell 格式: RUN <cmd>cmd 代表 shell 格式的命令
  • exec 格式: RUN ["可执行文件", "参数1", "参数2"]

需要注意的是:每个 RUN 指令都会新建立一层,所以正确的 Dockerfile 的写法是一个 RUN 指令后跟多条 shell 指令

FROM debian:stretch

RUN buildDeps='gcc libc6-dev make wget' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
# 清理掉中间文件,避免镜像臃肿
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

COPY : 复制文件

前面说过,Dockerfile 所在目录有可能需要额外文件帮助构建, COPY 命令就是将上下文的文件拷贝到镜像中。

# shell 格式
COPY [--chown=<user>:<group>] <src> <dst>
# exec 格式
COPY [--chown=<user>:<group>] ["<src>",..."<dst>"]

# 将上下文的 package.json 文件拷贝到镜像环境的 /usr/src/app/ 中
# COPY package.json /usr/src/app/
  • 如果 dst 中的目录不存在,Docker 会先行创建目录后再进行拷贝

ADD : 高级复制

ADD 命令格式与 COPY 基本一致,但是其 src 可以是一个 URL ,Docker 会到 URL 下载该文件。

如果 srctar 压缩格式的文件,Docker 也会解压缩该文件然后拷贝到目标路径去。

ADD 命令一般在需要自动解压缩场合时才会被使用,其他场合一般使用 COPY 命令

CMD : 容器启动

CMD 指令用于指定默认的容器主进程的启动命令,其格式和 RUN 相似:

# shell 格式
CMD <cmd>
# exec 格式
CMD ["可执行文件", "参数1", "参数2"...]
# 参数列表格式,在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数
CMD ["参数1","参数2"....]

docker run 命令中包含了启动命令,则会覆盖 CMD 命令中的设定:

# 使用 cat /etc/os-release 替代 CMD 
docker run -it ubuntu cat /etc/os-release

需要注意的是: CMD 命令中的命令都是以前台的方式运行,如果切换到后台,则意味着主进程退出了,整个 container 也会退出。

ENTRYPOINT : 入口点

ENTRYPOINT 也是用于指定容器启动程序及参数,其格式和 CMD 一致,当指定了 ENTRYPOINT 后,CMD 命令的含义就会扩展为:

# CMD 的内容作为参数传递给 ENTRYPOINT 命令
ENTRYPOINT "<CMD>"

docker run 命令包含了启动命名。并且指定了 ENTRYPOINT 后,此启动命令便会作为参数传递给 ENTRYPOINT ,相当于将 ENTRYPOINT 指定的命令进行扩展。

ENV : 设置环境变量

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2> ...

ARG : 构建参数

ENV 命令效果一样,但此命令作用域仅为当前这一层镜像

ARG <参数名>[=<默认值>]

VOLUME : 定义匿名卷

匿名卷用于定义一个默认的存储空间,存放进程运行时的输出数据,避免向镜像存储层写入大量数据。

VOLUME ["<路径1>","<路径2>"...]
VOLUME <路径>

如果使用 docker run 挂载了卷,则会覆盖该匿名卷。

EXPOSE : 暴露端口

声明容器运行时提供的服务端口

EXPOSE <端口1> [<端口2>...]

WORKDIR : 指定工作目录

# 指定工作目录,以后各层的当前目录都会受此指令的影响
WORKDIR <dir>

USER : 指定当前用户

该命令也会影响以后的层

USER <user name>[:<user group>]

HEALTHCHECK : 健康检查

用于告诉 Docker 应该如何进行判断容器的状态是否正常。

# 设置检查容器健康状况的命令
HEALTHCHECK [opt] CMD <cmd>
# 如果基础镜像有健康检查,使用此行屏蔽其健康检查命令
HEALTHCHECK NONE

ONBUILD : 为继承层设置指令

ONBUILD 后跟的指令,只有以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

ONBUILD <cmd>
Last Updated 2020-06-28 Sun 20:18.
Render by hexo-renderer-org with Emacs 26.3 (Org mode 9.3.7)