安装 docker

CentOS7 安装 docker-ce

  • 配置 yum 源

    1
    2
    3
    4
    5
    
    curl -Lo /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
    #替换成清华源
    sed -i 's#download.docker.com#mirrors.tuna.tsinghua.edu.cn/docker-ce#' /etc/yum.repos.d/docker-ce.repo
    yum clean all
    yum makecache
    
  • 安装 docker

    1
    
    yum install docker-ce
    
  • 修改 docker 配置文件,建议选择一个与本地网络不冲突的网段

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    mkdir -p /etc/docker
    cat > /etc/docker/daemon.json <<-EOF
    {
      "insecure-registries": ["harbor.colben.cn"],
      "default-address-pools" : [{"base":"10.110.0.0/16", "size": 24}],
      "log-driver": "json-file",
      "log-opts": {"max-size":"100m", "max-file":"4"}
    }
    EOF
    
  • 启动 docker

    1
    
    systemctl start docker
    

Linux with systemd 安装 docker

  • 下面是在运行 Rocky linux 8.4 的 X86 服务器上的操作过程

  • 下载 docker 二进制文件

    1
    
    curl -LO https://download.docker.com/linux/static/stable/x86_64/docker-20.10.10.tgz
    
  • 安装

    1
    2
    3
    4
    
    tar zxf docker-20.10.10.tgz
    mv docker/* /usr/bin/
    rm -rf docker/ docker-20.10.10.tgz
    groupadd -g 10110 docker
    
  • 创建 /usr/lib/systemd/system/containerd.service,内容如下

     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
    
    [Unit]
    Description=containerd container runtime
    Documentation=https://containerd.io
    After=network.target local-fs.target
    
    [Service]
    ExecStartPre=-/sbin/modprobe overlay
    ExecStart=/usr/bin/containerd
    
    Type=notify
    Delegate=yes
    KillMode=process
    Restart=always
    RestartSec=5
    # Having non-zero Limit*s causes performance problems due to accounting overhead
    # in the kernel. We recommend using cgroups to do container-local accounting.
    LimitNPROC=infinity
    LimitCORE=infinity
    LimitNOFILE=1048576
    # Comment TasksMax if your systemd version does not supports it.
    # Only systemd 226 and above support this version.
    TasksMax=infinity
    OOMScoreAdjust=-999
    
    [Install]
    WantedBy=multi-user.target
    
  • 创建 /usr/lib/systemd/system/container-getty@.service,内容如下

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    [Unit]
    Description=Container Getty on /dev/pts/%I
    Documentation=man:agetty(8) man:machinectl(1)
    After=systemd-user-sessions.service plymouth-quit-wait.service
    After=rc-local.service getty-pre.target
    Before=getty.target
    IgnoreOnIsolate=yes
    ConditionPathExists=/dev/pts/%I
    
    [Service]
    ExecStart=-/sbin/agetty --noclear --keep-baud pts/%I 115200,38400,9600 $TERM
    Type=idle
    Restart=always
    RestartSec=0
    UtmpIdentifier=pts/%I
    TTYPath=/dev/pts/%I
    TTYReset=yes
    TTYVHangup=yes
    KillMode=process
    IgnoreSIGPIPE=no
    SendSIGHUP=yes
    
  • 创建 /usr/lib/systemd/system/docker.socket,内容如下

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    [Unit]
    Description=Docker Socket for the API
    
    [Socket]
    ListenStream=/var/run/docker.sock
    SocketMode=0660
    SocketUser=root
    SocketGroup=docker
    
    [Install]
    WantedBy=sockets.target
    
  • 创建 /usr/lib/systemd/system/docker.service,内容如下

     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
    
    [Unit]
    Description=Docker Application Container Engine
    Documentation=https://docs.docker.com
    After=network-online.target firewalld.service containerd.service
    Wants=network-online.target
    Requires=docker.socket containerd.service
    
    [Service]
    Type=notify
    # the default is not to use systemd for cgroups because the delegate issues still
    # exists and systemd currently does not support the cgroup feature set required
    # for containers run by docker
    ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
    ExecReload=/bin/kill -s HUP $MAINPID
    TimeoutSec=0
    RestartSec=2
    Restart=always
    
    # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
    # Both the old, and new location are accepted by systemd 229 and up, so using the old location
    # to make them work for either version of systemd.
    StartLimitBurst=3
    
    # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
    # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
    # this option work for either version of systemd.
    StartLimitInterval=60s
    
    # Having non-zero Limit*s causes performance problems due to accounting overhead
    # in the kernel. We recommend using cgroups to do container-local accounting.
    LimitNOFILE=infinity
    LimitNPROC=infinity
    LimitCORE=infinity
    
    # Comment TasksMax if your systemd version does not support it.
    # Only systemd 226 and above support this option.
    TasksMax=infinity
    
    # set delegate yes so that systemd does not reset the cgroups of docker containers
    Delegate=yes
    
    # kill only the docker process, not all processes in the cgroup
    KillMode=process
    OOMScoreAdjust=-500
    
    [Install]
    WantedBy=multi-user.target
    
  • 修改 docker 配置文件,建议选择一个与本地网络不冲突的网段

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    mkdir -p /etc/docker
    cat > /etc/docker/daemon.json <<-EOF
    {
      "insecure-registries": ["harbor.colben.cn"],
      "default-address-pools" : [{"base":"10.110.0.0/16", "size": 24}],
      "log-driver": "json-file",
      "log-opts": {"max-size":"100m", "max-file":"4"}
    }
    EOF
    
  • 启动 docker

    1
    
    systemctl start docker
    

Linux with openrc 安装 docker

  • 下面是在运行 Alpine Linux 3.14.2 的树莓派 4B 上的操作过程

  • 下载 docker 二进制文件

    1
    
    curl -LO https://download.docker.com/linux/static/stable/aarch64/docker-20.10.10.tgz
    
  • 安装

    1
    2
    3
    4
    
    tar zxf docker-20.10.10.tgz
    mv docker/* /usr/bin/
    rm -rf docker/ docker-20.10.10.tgz
    addgroup -g 10110 docker
    
  • 创建 containerd 启动脚本 /etc/init.d/containerd

     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
    
    #!/sbin/openrc-run
    supervisor=supervise-daemon
    
    name="Container Daemon"
    description="Standalone containerd (usually started by Docker)"
    
    extra_started_commands="reload"
    description_reload="Reload configuration without exiting"
    
    command="${containerd_command:-/usr/bin/containerd}"
    command_args="${containerd_opts}"
    rc_ulimit="${ulimit_opts:--c unlimited -n 1048576 -u unlimited}"
    retry="${signal_retry:-TERM/60/KILL/10}"
    
    log_file="${log_file:-/var/log/${RC_SVCNAME}.log}"
    err_file="${err_file:-${log_file}}"
    log_mode="${log_mode:-0644}"
    log_owner="${log_owner:-root:root}"
    
    supervise_daemon_args="${supervise_daemon_opts:---stderr \"${err_file}\" --stdout \"${log_file}\"}"
    
    depend() {
            need sysfs cgroups
    }
    
    start_pre() {
            checkpath -f -m "$log_mode" -o "$log_owner" "$log_file" "$err_file"
    }
    
    reload() {
            ebegin "Reloading configuration"
            $supervisor $RC_SVCNAME --signal HUP
            eend $?
    }
    
  • 创建 docker 启动脚本 /etc/init.d/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
    
    #!/sbin/openrc-run
    supervisor=supervise-daemon
    
    name="Docker Daemon"
    description="Persistent process that manages docker containers"
    description_reload="Reload configuration without exiting"
    
    command="${DOCKERD_BINARY:-/usr/bin/dockerd}"
    command_args="${DOCKER_OPTS}"
    DOCKER_LOGFILE="${DOCKER_LOGFILE:-/var/log/${RC_SVCNAME}.log}"
    DOCKER_ERRFILE="${DOCKER_ERRFILE:-${DOCKER_LOGFILE}}"
    DOCKER_OUTFILE="${DOCKER_OUTFILE:-${DOCKER_LOGFILE}}"
    supervise_daemon_args="--stderr \"${DOCKER_ERRFILE}\" --stdout \"${DOCKER_OUTFILE}\""
    
    extra_started_commands="reload"
    
    rc_ulimit="${DOCKER_ULIMIT:--c unlimited -n 1048576 -u unlimited}"
    
    retry="${DOCKER_RETRY:-TERM/60/KILL/10}"
    
    depend() {
            need sysfs cgroups
            after iptables ip6tables
    }
    
    start_pre() {
            checkpath -f -m 0644 -o root:docker "$DOCKER_ERRFILE" "$DOCKER_OUTFILE"
    }
    
    reload() {
            ebegin "Reloading configuration"
            $supervisor $RC_SVCNAME --signal HUP
            eend $?
    }
    
  • 启动脚本增加可执行权限

    1
    
    chmod 0755 /etc/init.d/{containerd,docker}
    
  • 修改 docker 配置文件,建议选择一个与本地网络不冲突的网段

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    mkdir -p /etc/docker
    cat > /etc/docker/daemon.json <<-EOF
    {
      "insecure-registries": ["harbor.colben.cn"],
      "default-address-pools" : [{"base":"10.110.0.0/16", "size": 24}],
      "log-driver": "json-file",
      "log-opts": {"max-size":"100m", "max-file":"4"}
    }
    EOF
    
  • 启动 docker

    1
    
    service docker start
    
  • 设置 docker 开机自动启动

    1
    
    rc-update add docker
    

安装 docker-compose

  • 下载 docker-compose

    1
    
    curl -LO https://github.com/docker/compose/releases/download/v2.1.0/docker-compose-linux-x86_64
    
  • 安装

    1
    2
    
    mv docker-compose-linux-x86_64 /usr/bin/docker-compose
    chmod 0755 /usr/bin/docker-compose
    

安装 gojq

  • 该工具支持平台较多,无依赖,与 jq 命令操作完全一致,可用于替换 jq 命令

  • 下载

    1
    
    curl -LO https://github.com/itchyny/gojq/releases/download/v0.12.5/gojq_v0.12.5_linux_amd64.tar.gz
    
  • 安装

    1
    2
    3
    4
    
    tar zxf gojq_v0.12.5_linux_amd64.tar.gz
    mv gojq_v0.12.5_linux_amd64/gojq /usr/bin/
    chmod 0755 /usr/bin/gojq
    rm -rf gojq_*
    

基本命令

  • 镜像

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    docker pull [选项] [Docker Registry地址]<仓库名>:<标签> #获取镜像
    docker images [选项] #列出镜像
    docker images -f dangling=true #列出虚悬镜像
    docker images -q -f dangling=true | xargs docker rmi #删除全部虚悬镜像
    docker commit -m "提交的说明信息" -a "更新的用户信息" <容器ID> [地址]<仓库名>:<标签> #根据现有容器创建镜像
    docker build -t="[地址]<仓库名>:<标签>" <Dockerfile 所在的目录> #构建镜像
    docker tag <镜像ID> [地址]<仓库名>:<标签> #修改镜像的标签
    docker push [地址]<仓库名>:<标签> #上传镜像
    docker save -o <本地文件名.tar> [地址]<仓库名>:<标签> #保存镜像到本地文件
    docker load < <本地文件名.tar> #把本地文件加载到镜像库
    docker rmi <镜像ID> #删除镜像
    
  • 容器

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    docker run [选项] [地址]<仓库名>:<标签> [命令] #从镜像启动一个容器
    docker stop <容器名|容器ID> #终止运行中的容器
    docker start <容器名|容器ID> #启动已停止的容器
    docker retart <容器名|容器ID> #重新启动运行中的容器
    docker ps [-a] #查看(全部)容器信息
    docker logs <容器名|容器ID> #获取容器输出信息
    docker attach <容器名|容器ID> #进入运行中的容器
    docker export <容器ID> > <本地文件名.tar> #导出容器快照到本地文件
    cat <本地文件名.tar> | docker import - [地址]<仓库名>:<标签> #从本地文件导入容器快照
    docker rm -r <容器名|容器ID> #删除(运行中的)容器
    
  • 数据卷

    1
    2
    3
    4
    5
    6
    
    docker run [选项] -v /webapp [地址]<仓库名>:<标签> [命令] #启动容器时创建一个数据卷挂载到容器的 /webapp 下
    docker rm -v <容器名|容器ID> #删除容器时同时删除数据卷
    docker run [选项] -v <主机绝对目录>:<容器绝对目录>[:ro] [地址]<仓库名>:<标签> [命令] #启动容器时挂载本地目录到容器指定目录下,默认可读写
    docker run [选项] -v <主机文件>:<容器文件>[:ro] [地址]<仓库名>:<标签> [命令] #启动容器时挂载本地文件到容器指定文件,默认可读写
    docker inspect <容器名|容器ID> #查看容器信息
    docker run [选项] --volumes-from <挂载数据卷的容器名> [地址]<仓库名>:<标签> [命令] #在其他容器中挂载指定容器(不必运行)的数据卷
    
  • 备份数据卷

    1
    
    docker run [选项] --volumes-from <挂载数据卷的容器名> -v $(pwd):/backup [地址]<仓库名>:<标签> tar cvf /backup/backup.tar <数据卷挂载目录> #备份数据卷到主机当前目录的 backup.tar 文件
    
  • 恢复数据卷

    1
    2
    3
    
    docker run [选项] -v <数据卷挂载目录> --name <自定义一个容器名> [地址]<仓库名>:<标签> [命令] #创建一个带空数据卷的容器
    docker run [选项] --volumes-from <第一步挂载空数据卷的容器名> -v $(pwd):/backup busybox tar xvf /backup/backup.tar #挂载空数据卷和本机备份目录,解压备份文件
    docker run [选项] --volumes-from <第一步挂载空数据卷的容器名> busybox 'ls <数据卷挂载目录>' #查看恢复的数据
    
  • 网络

    1
    2
    3
    4
    
    docker run [选项] -P [地址]<仓库名>:<标签> [命令] #随机映射主机 49000-49900 中的端口到容器开放的端口
    docker run [选项] -p <ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort>[/udp] [地址]<仓库名>:<标签> [命令] #映射本机指定tcp(udp)端口到容器指定tcp(udp)端口
    docker port <容器名> <容器开放的端口> #查看主机被绑定的地址
    docker run [选项] --link <待链接容器名>:<链接别名> [地址]<仓库名>:<标签> [命令] #创建一个链接到其他容器的新容器
    

Dockerfile

  • 井号 “#” 后是注释
  • FROM 基础镜像
  • MAINTAINER 维护者信息
  • RUN shell命令
  • ADD 复制本地文件到容器,自动解压 tar 文件,可以增加网络文件
  • COPY 复制本地文件到容器,不自动解压,也不可以增加网络文件
  • LABEL 为镜像添加元数据
  • ENV 设置镜像内环境变量
  • USER 容器运行时的用户和用户组
  • ONBUILD 镜像触发器
  • EXPOSE 向外部开放端口
  • CMD 容器启动后运行的程序

docker 镜像仓库

官方 registry

  • 直接 docker 启动
    1
    2
    3
    4
    5
    6
    
    docker run -d \
        --name registry \
        --net host \
        -e "REGISTRY_HTTP_ADDR='0.0.0.0:80'" \
        -v /some/path:/var/lib/registry \
        registry
    

VMWare Harbor

  • 安装参考这里

  • docker registry 采用 http 协议,客户端提示 “server gave HTTP response to HTTPS client”

    1
    2
    3
    4
    
    #在客户端 /etc/docker/daemon.json 中增加 insecure-registries 配置
    #    "insecure-registries":["10.0.2.22:5080"]
    #重启客户端的 docker 服务
    systemctl restart docker
    
  • docker registry 采用 https 协议,客户端提示 “authority unknown …”

    1
    2
    3
    4
    5
    6
    
    #在客户端 /etc/docker/ 下创建 registry server 的 domain/ip 目录
    mkdir -p /etc/docker/certs.d/10.0.2.22:5080/
    #复制 registry server 的 ca.crt (该文件由 openssl 创建密钥时生成)
    scp root@10.0.2.22:/opt/harbor/keys/ca.crt /etc/docker/certs.d/10.0.2.22:5080/
    #重启客户端的 docker 服务
    systemctl restart docker