Docker命令使用经验总结

0x00 前言

Docker作为现在常用的服务部署方式,日常工作中免不了要做些buildpush之类的操作。为了避免每次都要查文档,这里将一些常用的命令和技巧做一些总结。

以下以Ubuntu 16.04 x64系统作为演示环境。

0x01 环境准备

安装docker

$ apt install docker
$ docker --version
Docker version 18.06.1-ce, build e68fc7a

重启docker服务

$ systemctl daemon-reload
$ systemctl restart docker

设置docker代理

此代理主要用于docker访问镜像仓库

创建配置文件:/etc/systemd/system/docker.service.d/http-proxy.conf,写入以下内容:

[Service]
Environment="HTTP_PROXY=http://web-proxy.com:8080" "HTTPS_PROXY=http://web-proxy.com:8080" "NO_PROXY=internal.com"

重启docker服务,配置生效

0x02 编写Dockerfile

要编译docker镜像,需要先编写Dockerfile文件。以下是一个Dockerfile的例子:

FROM python:2.7
# 基于python2.7镜像

RUN apt update && apt install python-pip -y \
    && rm -rf /var/lib/apt/lists/* \
    && pip install uwsgi \
    && pip install tornado \
    && mkdir /data
# 编译时执行的命令,需要尽量写成一条命令

WORKDIR /data
# 设置工作目录

COPY adb /usr/bin/
# 拷贝文件
COPY api/ /data/api/
# 拷贝目录

VOLUME ["/data1","/data2"]
# 挂载目录

ENV TZ="Asia/Shanghai"
# 设置时区

EXPOSE 80/tcp 8080/tcp
# 暴露服务端口

ENTRYPOINT sh /data/start.sh
# 指定入口命令,如果这个命令退出,docker容器也会一起退出

可以看出,格式还是相对比较简单的,照着例子,基本都能写出来。

ADD与COPY指令的区别

两者都可以用于向镜像中添加文件/目录,主要区别是:COPY只能添加本地文件/目录,ADD可以添加url指向的文件;并且,ADD如果指定的源地址是一个本地的tar文件,还会自动解压到目标目录中。

ENTRYPOINT和CMD指令的区别

两者都可以设置docker run的入口命令行,如果指定了多个,只有最后一个生效,两者主要区别是:如果Dockerfile中同时存在ENTRYPOINTCMD,只有ENTRYPOINT会执行;ENTRYPOINT配置的命令行允许被--entrypoint参数覆盖,而CMD配置的命令行允许被启动参数覆盖。

因此,优先级顺序是:

–entrypoint > ENTRYPOINT > 启动参数 > CMD

HEALTHCHECK

这是docker 1.12新增的指令,可以用于检查容器的健康状态。

HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
  CMD curl -fs http://localhost/ || exit 1

上面的指令是用来检测web服务是否正常方法,如果重试5次都失败后,容器状态会变成unhealthy,可以使用docker inspect命令查看容器状态。

ONBUILD

这条指令允许在使用当前镜像作为基础镜像去构建的时候触发,也就是说,在构建当前镜像时并不会触发这条指令。

ONBUILD COPY ./package.json /app
ONBUILD RUN [ "npm", "install" ]

0x03 编译镜像

$ docker build -t demo . 

表示使用当前目录的Dockerfile构建镜像demo

指定代理

如果要指定编译时的HTTP代理,可以使用--build-arg参数:

$ docker build -t demo . --build-arg http_proxy=http://web-proxy.com:8080

指定dns服务器

如果要指定编译时的dns服务器,可以修改docker的配置文件:/etc/docker/daemon.json,增加以下配置,并重启docker服务。

"dns": ["10.0.0.1"]

设置默认镜像源

在配置文件:/etc/docker/daemon.json中增加以下配置项,并重启docker服务。

"registry-mirrors": ["https://mirror.ccs.tencentyun.com"]

上面的镜像源是在腾讯云内部使用的镜像源地址。

指定Dockerfile路径

如果Dockerfile文件不在当前目录下,可以在docker build命令中使用-f /path/to/Dockerfile参数来制定Dockerfile文件的路径。

查看镜像的层信息

$ docker history demo
IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
9088b64a2ef3        15 seconds ago       /bin/sh -c #(nop)  ENTRYPOINT ["/bin/sh" "-c…   0B                  
6949219d8872        16 seconds ago       /bin/sh -c #(nop)  EXPOSE 80/tcp 8080/tcp       0B                  
80ff6b9185da        16 seconds ago       /bin/sh -c #(nop)  ENV TZ=Asia/Shanghai         0B                  
d069fdc8190a        58 seconds ago       /bin/sh -c #(nop) COPY file:f005afea09a30b4d…   10B                 
a09c0e999ca0        About a minute ago   /bin/sh -c #(nop) WORKDIR /data                 0B                  
28ed536148c6        About a minute ago   |0 /bin/sh -c apt update && apt install pyth…   35.4MB              
d8690ef56706        2 years ago          /bin/sh -c #(nop)  CMD ["python2"]              0B                  
<missing>           2 years ago          /bin/sh -c pip install --no-cache-dir virtua…   6.37MB              
<missing>           2 years ago          /bin/sh -c set -ex;   wget -O get-pip.py 'ht…   5.26MB              
<missing>           2 years ago          /bin/sh -c #(nop)  ENV PYTHON_PIP_VERSION=9.…   0B                  
<missing>           2 years ago          /bin/sh -c set -ex  && buildDeps='   dpkg-de…   45.6MB              
<missing>           2 years ago          /bin/sh -c #(nop)  ENV PYTHON_VERSION=2.7.14    0B                  
<missing>           2 years ago          /bin/sh -c #(nop)  ENV GPG_KEY=C01E1CAD5EA2C…   0B                  
<missing>           2 years ago          /bin/sh -c apt-get update && apt-get install…   8.67MB              
<missing>           2 years ago          /bin/sh -c #(nop)  ENV LANG=C.UTF-8             0B                  
<missing>           2 years ago          /bin/sh -c #(nop)  ENV PATH=/usr/local/bin:/…   0B                  
<missing>           2 years ago          /bin/sh -c set -ex;  apt-get update;  apt-ge…   324MB               
<missing>           2 years ago          /bin/sh -c apt-get update && apt-get install…   123MB               
<missing>           2 years ago          /bin/sh -c set -ex;  if ! command -v gpg > /…   0B                  
<missing>           2 years ago          /bin/sh -c apt-get update && apt-get install…   44.6MB              
<missing>           2 years ago          /bin/sh -c #(nop)  CMD ["bash"]                 0B                  
<missing>           2 years ago          /bin/sh -c #(nop) ADD file:f1509ab9c2cd38107…   123MB               

使用--no-trunc参数可以显示完整信息

0x04 运行容器

$ docker run -it demo bash

使用-d参数可以在后台启动容器。

指定运行时的dns服务器

$ docker run -i --dns=10.0.0.1 demo

指定运行时的环境变量

$ docker run -i --env http_proxy=http://web-proxy.com:8080 demo

挂载主机目录

$ docker run -i -v /home/ubuntu/data:/data demo

这样可以把主机上的/home/ubuntu/data目录挂载到容器里的/data下。

映射端口

默认情况下无法从外部访问容器内的服务,但是可以通过在启动容器时加上-p port1:port2参数,将容器内的端口port2映射到本机的port1端口。

覆盖ENTRYPOINT

使用--entrypoint参数可以覆盖Dockerfile中配置的ENTRYPOINT命令行,但是需要注意的是:如果需要传参的话需要写成--entrypoint mongod mongo:latest --replSet rs0这样的形式,也就是命令和参数是分开的。

进入容器shell

$ docker ps
CONTAINER ID  IMAGE  COMMAND                       CREATED          STATUS           PORTS              NAMES
e6ae7638a58d  demo   "/bin/sh -c '/data/start.sh'" 8 seconds ago    Up 7 seconds    80/tcp, 8080/tcp   loving_neumann

$ docker exec -i -t e6ae7638a58d sh
# id
uid=0(root) gid=0(root) groups=0(root)

如果默认进去的不是root权限,可以增加-u root参数。

清理磁盘空间

$ docker system prune -a -f

0x05 登录docker仓库

登录官方仓库

$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: drunkdream
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

登录非官方仓库

$ docker login hub.tencentyun.com
Username: drunkdream
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

如果仓库使用的不是HTTPS的443端口,需要在主机名后面加上:port

如果提示以下错误:

Error response from daemon: Get https://hub.private.com:8080/v2/: http: server gave HTTP response to HTTPS client

说明Server不支持HTTPS协议,需要在配置文件:/etc/docker/daemon.json中增加以下配置:

"insecure-registries": ["hub.private.com:8080"]

重启docker服务,再登录就可以了

登录协议

抓包可得以下结果:

GET /v2/ HTTP/1.1
Host: hub.private.com:8080
User-Agent: docker/18.06.1-ce go/go1.10.4 git-commit/e68fc7a kernel/4.10.0-28-generic os/linux arch/amd64 UpstreamClient(Docker-Client/18.06.1-ce \(linux\))
Authorization: Basic YWRtaW46YWRtaW4=
Accept-Encoding: gzip
Connection: close

HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Date: Mon, 25 Feb 2019 04:09:50 GMT
Docker-Distribution-Api-Version: registry/2.0
X-Content-Type-Options: nosniff
Connection: close

{}

说明: docker是使用了HTTP协议的Authorization头进行了身份认证,很容易获取明文密码。因此,为了安全,一定要使用HTTPS协议。

0x06 push新镜像到仓库

查询镜像

$ docker search python
NAME                             DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
python                           Python is an interpreted, interactive, objec…   5022                [OK]                
django                           Django is a free web application framework, …   941                 [OK]                
pypy                             PyPy is a fast, compliant alternative implem…   234                 [OK]                
kaggle/python                    Docker image for Python scripts run on Kaggle   138                                     [OK]
arm32v7/python                   Python is an interpreted, interactive, objec…   48                                      
joyzoursky/python-chromedriver   Python with Chromedriver, for running automa…   43                                      [OK]
nikolaik/python-nodejs           Python with Node.js                             40                                      [OK]
centos/python-35-centos7         Platform for building and running Python 3.5…   38                                      
circleci/python                  Python is an interpreted, interactive, objec…   37                                      
centos/python-36-centos7         Platform for building and running Python 3.6…   28                                      
hylang                           Hy is a Lisp dialect that translates express…   27                  [OK]                
arm64v8/python                   Python is an interpreted, interactive, objec…   21                                      
centos/python-27-centos7         Platform for building and running Python 2.7…   17                                      
publicisworldwide/python-conda   Basic Python environments with Conda.           6                                       [OK]
bitnami/python                   Bitnami Python Docker Image                     6                                       [OK]
dockershelf/python               Repository for docker images of Python. Test…   5                                       [OK]
i386/python                      Python is an interpreted, interactive, objec…   3                                       
centos/python-34-centos7         Platform for building and running Python 3.4…   2                                       
komand/python-plugin             DEPRECATED: Komand Python SDK                   2                                       [OK]
ppc64le/python                   Python is an interpreted, interactive, objec…   2                                       
amd64/python                     Python is an interpreted, interactive, objec…   1                                       
ccitest/python                   CircleCI test images for Python                 0                                       [OK]
s390x/python                     Python is an interpreted, interactive, objec…   0                                       
openshift/python-33-centos7      DEPRECATED: A Centos7 based Python v3.3 imag…   0                                       
saagie/python                    Repo for python jobs                            0                                       

如果想获取python镜像的tag列表,可以使用以下命令:

$ wget -q https://registry.hub.docker.com/v1/repositories/python/tags -O -  | sed -e 's/[][]//g' -e 's/"//g' -e 's/ //g' | tr '}' '\n'  | awk -F: '{print $3}'

拉取镜像到本地

$ docker pull python
Using default tag: latest
latest: Pulling from library/python
741437d97401: Pull complete 
34d8874714d7: Pull complete 
0a108aa26679: Pull complete 
7f0334c36886: Pull complete 
65c95cb8b3be: Pull complete 
9107d7193263: Pull complete 
dd6f212ec984: Pull complete 
43288b101abf: Pull complete 
89dd65885f16: Pull complete 
Digest: sha256:a570ef00b7348c85b546c0e67955fa3be233c27bc2379d0f87fc8e4ff25aa006
Status: Downloaded newer image for python:latest

打标签

$ docker tag python:latest hub.tencentyun.com/drunkdream/python:latest

如果要push到非官方仓库,需要在打tag时加上仓库的地址。

push镜像到仓库

$ docker push hub.tencentyun.com/drunkdream/python:latest
The push refers to repository [hub.tencentyun.com/drunkdream/python:latest]
b2f7bd391363: Pushed 
08a5b66845ac: Pushed 
88a85bcf8170: Pushed 
65860ac81ef4: Pushed 
a22a5ac18042: Pushed 
6257fa9f9597: Pushed 
578414b395b9: Pushed 
abc3250a6c7f: Pushed 
13d5529fd232: Pushed 
latest: digest: sha256:35a3001b1defafa4611f764a9c6d07c2146aefc17be2c24ee0200fd37b19b1c7 size: 2218

0x07 镜像导出与导入

镜像导出

$ docker save -o demo.tar demo:latest

镜像导入

$ docker load -i demo.tar

0x08 Compose

Compose项目是Docker官方的开源项目,实现了对Docker容器集群的快速编排。从功能上看,跟OpenStack中的Heat十分类似。

其代码在https://github.com/docker/compose上开源。

安装

$ pip install docker-compose

编写docker-compose.yml

这个文件描述了容器之间的关系。

version: '3'
services:

  webapp:
    build: . 
    # Dockerfile所在目录
    dockerfile: Dockerfile
    # Dockerfile 文件名
    command: echo "hello world"
    # 覆盖容器启动后的默认命令
    depends_on:
      - db
      - redis
    # 服务依赖
    dns:
      - 8.8.8.8
      - 114.114.114.114
    # 配置DNS
    env_file: .env
    # 指定环境变量文件
    environment:
      - DEBUG=1
    # 设置环境变量
    expose:
      - "8080"
    # 暴露端口,只在服务间被访问
    extra_hosts:
      - "www.drunkdream.com:1.1.1.1"
    # 添加额外hosts
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 10s
      timeout: 5s
      retries: 3
    # 健康检查
    image: ubuntu
    # 指定镜像
    ports:
      - "80"
      - "8080:80"
      - "127.0.0.1:8001:8001"
    # 映射端口,格式为:HOST:CONTAINER
    volumes:
      - "/localhost/postgres.sock:/var/run/postgres/postgres.sock"
      - "/localhost/data:/var/lib/postgresql/data"
    # 磁盘映射
    networks:
      - front-tier
      - back-tier
    # 配置网络

networks:
  front-tier:
    driver: bridge
  back-tier:
    driver: bridge

常用命令

$ docker-compose up

启动所有服务,使用-d参数可以在后台启动服务,-f参数可以指定docker-compose.yml。

$ docker-compose down

停止和删除容器、网络

$ docker-compose logs

查看日志

$ docker-compose build

构建所有容器

分享