一、Docker 简介

官网:http://www.docker.com

帮助文档链接: https://docs.docker.com

docker 镜像仓库: https://hub.docker.com

docker 中文网站: http://www.docker.org.cn

a.什么是 Docker

  • 基于 Linux 内核的 Cgroup,Namespace,以及 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术,由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
  • 最初实现是基于 LXC,从 0.7 以后开始去除 LXC,转而使用自行开发的 Libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 Containerd。
  • Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护,使得 Docker 技术比虚拟机技术更为轻便、快捷。

b.Docker 的优势

  • 快速部署:短时间内可以部署成百上千个应用,更快速交付到线上。
  • 高效虚拟化:不需要额外的hypervisor支持,直接基于linux 实现应用虚拟化,相比虚拟机大幅提高性能和效率。
  • 节省开支:提高服务器利用率,降低IT支出。
  • 简化配置:将运行环境打包保存至容器,使用时直接启动即可。
  • 快速迁移和扩展:可夸平台运行在物理机、虚拟机、公有云等环境,良好的兼容性可以方便将应用从A宿主机迁移到B宿主机,甚至是A平台迁移到B平台

虚拟机与Docker容器运行对比图

c.Docker核心组件和体系结构

  • Docker 主机(Host): 一个物理机或虚拟机,用于运行Docker服务进程和容器,也称为宿主机,node节点
  • Docker 服务端(Server): Docker守护进程,运行docker容器
  • Docker 客户端(Client): 客户端使用 docker 命令或其他工具调用docker API
  • Docker 镜像(Images): 镜像可以理解为创建实例使用的模板,本质上就是一些程序文件的集合
  • Docker 仓库(Registry): 保存镜像的仓库https://hub.docker.com,企业内部一般会搭建私有仓库harbor
  • Docker 容器(Container): 容器是从镜像生成对外提供服务的一个或一组服务,其本质就是将镜像中的程序启动后生成的进程

d、容器的创建与管理过程

1、dockerd通过grpc和containerd模块通信(runc)交换,dockerd和containerd通信的socket文件: /run/containerd/containerd.sock

2、containerd在dockerd启动的时候被启动,然后containerd启动grpc请求监听,containerd处理grpc请求,根据请求做相应动作

3、若是创建容器,containerd拉起一个container-shim容器进程,并进行相应的创建操作

4、container-shim被拉起来后,start/exec/create拉起runC进程,通过exit/control文件和containerd通信,通过父子进程关系和SIGCHLD(信号)监控容器中进程状态

5、在整个容器生命周期中,containerd通过epoll监控容器文件,监控容器事件

二、Docker 容器的底层实现原理

Docker容器底层主要使用了Linux内核中的CGroups、Namespace和Union File System等技术。

  • Namespace: 用于隔离应用程序的进程空间、网络空间、文件系统空间和用户空间,避免不同容器之间的相互干扰;
  • CGroups: 用于将进程及其子进程分配到不同的组中,从而对系统资源进行管理和限制;
  • Union File System: 用于将不同的文件系统进行联合,从而实现应用程序的可移植性和独立性。

a.Linux Namespace

namespace是Linux系统的底层概念,在内核层实现,即有一些不同类型的命名空间被部署在核内,各个docker容器运行在同一个docker主进程并且共用同一个宿主机系统内核,各docker容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程内实现运行指定服务的运行环境,并且还可以保护宿主机内核不受其他进程的干扰和影响,如文件系统空间、网络空间、进程空间等,目前主要通过以下技术实现容器运行空间的相互隔离

Namespace类型 功能 系统调用参数 内核版本
MNT Namespace(mount) 提供磁盘挂载点和文件系统的隔离能力 CLONE_NEWNS Linux 2.4.19
IPC Namespace(Inter-Process Communication) 提供进程间通信的隔离能力 CLONE_NEWIPC Linux 2.6.19
UTS Namespace(UNIX Timesharing System) 提供主机名隔离能力 CLONE_NEWUTS Linux 2.6.19
PID Namespace(Process Identification) 提供进程隔离能力 CLONE_NEWPID Linux 2.6.24
Net Namespace(network) 提供网络隔离能力 CLONE_NEWNET Linux 2.6.29
User Namespace(user) 提供用户隔离能力 CLONE_NEWUSER Linux 3.8
Cgroup Namespace 提供进程所属的控制组的身份隔离 CLONE_NEWCGROUP Linux 4.6
Time Namespace 提供时间隔离能力 CLONE_NEWTIME Linux 5.6

查看当前系统支持哪些namespace

lsns -l 

容器进程隔离示例图

b.Linux CGroups

  1. Cgroups (Control Groups)是 Linux 下用于对一个或一组进程进行资源控制和监控的机制;
  2. 可以对诸如 CPU 使用时间、内存、磁盘 I/O 等进程所需的资源进行限制;
  3. 不同资源的具体管理工作由相应的 Cgroup 子系统(Subsystem)来实现 ;
  4. 针对不同类型的资源限制,只要将限制策略在不同的的子系统上进行关联即可 ;
  5. Cgroups 在不同的系统资源管理子系统中以层级树(Hierarchy)的方式来组织管理:每个 Cgroup 都可以包含其他的子 Cgroup,因此子 Cgroup 能使用的资源除了受本 Cgroup 配置的资源参数限制,还受到父Cgroup 设置的资源限制 。

cpu子系统示例图:

c.Union File System (UnionFS)

最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下。

比如,现在有两个目录 A 和 B,它们分别有两个文件:

$ tree
.
├── A
│  ├── a
│  └── x
└── B
  ├── b
  └── x

然后,使用联合挂载的方式,将这两个目录挂载到一个公共的目录 C 上:

$ mkdir C
$ mount -t aufs -o dirs=./A:./B none ./C

这时,我再查看目录 C 的内容,就能看到目录 A 和 B 下的文件被合并到了一起:

$ tree ./C
./C
├── a
├── b
└── x

三、Docker 安装和配置

a. 操作系统要求

CentOS 6 因内核太旧,即使支持安装docker,但会有各种问题,不建议安装
CentOS 7 的 extras 源虽然可以安装docker,但包比较旧,建议从官方源或镜像源站点下载安装docker

b.通用安装docker脚本

[root@centos7 ~]#  curl -fsSL get.docker.com -o get-docker.sh
[root@centos7 ~]#  sh get-docker.sh --mirror Aliyun

c.CentOS 7 系统在线安装以及离线rpm包部署docker

###################   CentOS7联网在线安装 docker服务  ##########################
#CentOS 7 安装docker依赖基础yum源:Base,Extras   这里使用阿里云的镜像源
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

# step 1: 安装必要的一些系统工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# step 2: 添加软件源信息
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# step 3: 替换官方仓库为阿里云仓库
sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# step 4: 更新并安装Docker-CE,
yum makecache fast
yum -y install docker-ce
# step 5: 启动docker并配置开机自启
systemctl start docker && systemctl enable docker

###################   CentOS7离线rpm包安装 docker服务  ##########################
## 首先需要在联网机器上下载好docker需要到各种依赖包,前提是该机器之前没有安装过docker,否则可能会出现包下载不全,在不联网到机器无法顺利部署

# step 1: 创建临时存放rpm包目录
mkdir $HOME/docker-packages
# step 2:下载镜像所依赖的所有rpm包到本地,默认安装仓库内最新版本
yum install --downloaddir=$HOME/docker-packages/ --downloadonly docker-ce
# step 3: 打包下载好的镜像目录
cd $HOME  && tar -czvf docker-packages.tar.gz docker-packages
# step 4: 使用ftp等工具传到无法联网的机器上,比如用户家目录然后解压、安装
cd $HOME $$ tar -zxvf docker-packages.tar.gz
cd docker-packages && yum localinstall *.rpm 

# 注意:
# 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。
# vim /etc/yum.repos.d/docker-ce.repo
#   将[docker-ce-test]下方的enabled=0修改为enabled=1
#
# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
yum list docker-ce.x86_64 --showduplicates | sort -r
#   Loading mirror speeds from cached hostfile
#   Loaded plugins: branch, fastestmirror, langpacks
#   docker-ce.x86_64            17.03.1.ce-1.el7.centos            docker-ce-stable
#   docker-ce.x86_64            17.03.1.ce-1.el7.centos            @docker-ce-stable
#   docker-ce.x86_64            17.03.0.ce-1.el7.centos            docker-ce-stable
#   Available Packages
# Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos)
sudo yum -y install docker-ce-[VERSION]

d.Ubuntu系统在线安装以及离线使用deb包部署docker

###################   Ubuntu联网在线安装 docker服务  ##########################
# step 1: 安装必要的一些系统工具
sudo apt-get update
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
# step 2: 安装GPG证书
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# Step 3: 写入软件源信息
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# Step 4: 更新并安装Docker-CE
sudo apt-get -y update
sudo apt-get -y install docker-ce

# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
apt-cache madison docker-ce
#   docker-ce | 17.03.1~ce-0~ubuntu-xenial | https://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages
#   docker-ce | 17.03.0~ce-0~ubuntu-xenial | https://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages
# Step 2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.1~ce-0~ubuntu-xenial)
apt-get -y install docker-ce=[VERSION]

###################   Ubuntu离线deb包安装 docker服务  ##########################

## 首先需要在联网机器上下载好docker需要到各种依赖包,前提是该机器之前没有安装过docker,否则可能会出现包下载不全,在不联网到机器无法顺利部署

# 查看镜像仓库有哪些docker版本可通过命令查看:apt-cache madison docker-ce
# Step 1: Ubuntu下载好的dpkg包默认存放在/var/cache/apt/archives/ 目录下,所以需要提前清空该目录
rm -rf /var/cache/apt/archives/*
# Step 2: 安装指定版本
apt-get install -d docker-ce=5:20.10.17~3-0~ubuntu-jammy
# Step 3: 打包下载好的软件目录,传到不联网的机器上,如用户家目录
cd /var/cache/apt/  && tar -czvf docker-packages.tar.gz archives
## 3、登录不联网机器部署
cd $HOME && tar -zxvf docker-packages.tar.gz
cd archives && dpkg -i *.deb

e.二进制安装

本方法适用于无法上网或无法通过包安装方式安装的主机上安装docker

官方网站docker二进制安装程序下载路径:https://download.docker.com/linux/static/stable/x86_64/

清华大学镜像源docker二进制安装下载路径: https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/static/stable/x86_64/

阿里云镜像源docker二进制安装下载路径:https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/

示例,CentOS7服务器二进制安装docker-ce

# 下载二进制包,可在能联网的机器下载该程序包,然后传输至不能联网的服务器上
[root@centos7 ~] wget https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/docker-20.10.24.tgz
# 登录到要部署docker服务的机器上做基础环境优化
[root@centos7 ~]  systemctl stop firewalld && systemctl disable firewalld && echo "防火墙已关闭" && sleep 1
[root@centos7 ~]  sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux && setenforce  0 
[root@centos7 ~] cat > /etc/security/limits.conf <<-EOF
*             soft    core            unlimited
*             hard    core            unlimited
*             soft    nproc           1000000
*             hard    nproc           1000000
*             soft    nofile          1000000
*             hard    nofile          1000000
*             soft    memlock         32000
*             hard    memlock         32000
*             soft    msgqueue        8192000
*             hard    msgqueue        8192000
EOF

[root@centos7 ~] cat > /etc/sysctl.conf <<-EOF
net.ipv4.ip_forward=1
vm.max_map_count=262144
kernel.pid_max=4194303
fs.file-max=1000000
net.ipv4.tcp_max_tw_buckets=6000
net.netfilter.nf_conntrack_max=2097152

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
vm.swappiness=0

EOF
# 加载优化后的配置
[root@centos7 ~]  sysctl -p
# 登录到要部署docker服务的机器上做基础环境优化
[root@centos7 ~] tar xvf docker-20.10.24.tgz
[root@centos7 ~] cp docker/* /usr/local/bin/  #注意此路径需要跟后面制作的service文件内的路径匹配

# 制作service文件后通过systemctl命令启动,需要制作三个文件:docker.service docker.socket containerd.service
# ###################   制作 docker.service 文件  ##########################
[root@centos7 ~] cat > /lib/systemd/system/docker.service <<-EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service time-set.target
Wants=network-online.target containerd.service
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/local/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF

# ###################   制作 docker.socket 文件  ##########################
[root@centos7 ~] cat > /lib/systemd/system/docker.socket <<-EOF
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF

# ###################   制作 containerd.service 文件  ##########################
[root@centos7 ~] cat > /lib/systemd/system/containerd.service<<-EOF
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/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=infinity
# 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
EOF

#  创建docker用户
[root@centos7 ~] groupadd docker && useradd docker -g docker
#  启动docker服务
[root@centos7 ~]  systemctl enable containerd docker  && systemctl start containerd docker

f. Docker 配置

docker默认使用的配置文件为 /etc/docker/daemon.json,所以可以通过修改改配置文件为docker容器开启更多特性

daemon.json常用的配置选项

{
"debug": true # 调试docker daemon时开启,设为true将输出详细的日志信息
"log-level": "info" # 设置Docker日志的详细级别,可选值为 “debug”, “info”, “warn”, “error”, “fatal” 或 “panic”
"storage-driver": "overlay2" #指定Docker的存储驱动,常见的选项包括 “overlay2”、“aufs”、“devicemapper” 和 “zfs”。
"data-root": "/var/lib/docker" # 指定Docker存储容器和镜像的根目录,早期使用graph参数
"registry-mirrors": ["https://mirror.example.com"] # 配置Docker镜像仓库的镜像地址,用于加速镜像的拉取
"insecure-registries": ["registry.example.com"] # 允许连接到不安全(未加密或未经身份验证)的镜像仓库
"log-driver": "json-file", # 用于配置Docker守护进程的日志驱动程序,支持多种日志后端,例如Syslog、journald,以及以JSON格式写入文件等等
"log-opts": {
      "max-size": "100m", #max-size:单个日志文件的最大大小
      "max-file": "5" #最多保留几个日志文件,当单个文件的日志大小超过设置后,会产生新的日志文件
 }
"live-restore": true # 当 Docker 守护进程终止时,它将关闭正在运行的容器。可以配置该守护进程,以便在该守护进程不可用时容器仍在运行。实时还原选项有助于减少由于守护进程崩溃、计划中断或升级而导致的容器停机时间。
"exec-opts": ["native.cgroupdriver=systemd"] #令容器运行时和 kubelet 使用 systemd 作为 cgroup 驱动,使系统更为稳定
"bip": "192.168.12.1/16" # docker的默认ip是172.17.0.1,当其网段与局域网段冲突时可以通过该配置手动更改
"max-concurrent-downloads" # 指定拉取镜像时的最大并发数,默认为3。
}

配置取消warning警告

# 安装完docker后执行docker info如果出现如下告警:
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled

vim /etc/sysctl.conf
添加以下内容
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

1、配置镜像加速

访问网址 https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 登录阿里云获取镜像加速器地址,该页面上同时也提供了配置镜像加速器的方法,只需要依次执行下面的命令就可以了(把中括号里的加速器地址换成自己登录阿里云获取到的地址)即可

[root@centos7 ~]  mkdir -p /etc/docker
[root@centos7 ~]  tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://h03gcjvp.mirror.aliyuncs.com","https://dockerproxy.com"]
}
EOF
[root@centos7 ~] systemctl daemon-reload  && systemctl restart docker
# 国内镜像源很多,比如 :https://registry.docker-cn.com  https://docker.mirrors.ustc.edu.cn
# https://hub-mirror.c.163.com/  https://reg-mirror.qiniu.com等等都可以,配置多个,多个地址之间用逗号隔开即可

2、配置普通用户可以操作docker

## 1、添加普通用户到docker用户组,下面以yuhao用户做示例
[root@centos7 ~]  usermod -aG docker yuhao
# 让用户组的改变生效
[root@centos7 ~]  newgrp docker 
## 2、查看yuhao用户是否加入了docker用户组
[root@centos7 ~]  id yuhao
uid=1001(yuhao) gid=1001(yuhao) groups=1001(yuhao),1000(docker)
## 3、切换到yuhao用户,查看是否有权限执行docker命令
[root@centos7 ~] docker run hello-world
...

g. Docker 服务卸载

CentOS7系统卸载Docker服务

参考官方文档: https://docs.docker.com/engine/install/centos/

#卸载docker-ce安装包
[root@centos7 ~] yum remove docker  docker-client \
docker-client-latest docker-common docker-latest \
docker-latest-logrotate docker-logrotate docker-engine

#删除docker资源存放的相关文件
[root@centos7 ~] rm -rf /var/lib/docker

Ubuntu系统卸载Docker服务

参考官方文档: https://docs.docker.com/engine/install/ubuntu/

#卸载docker-ce安装包
[root@ubuntu ~] 
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done

#删除docker资源存放的相关文件
[root@ubuntu ~] rm -rf /var/lib/docker

四、Docker 操作基础命令

a.docker镜像相关操作命令

[root@centos7 ~] docker search centos:7.9.2009 #搜索镜像
[root@centos7 ~] docker images #查看本地所有镜像
[root@centos7 ~] docker build  #从dockerfile 构建镜像
[root@centos7 ~] docker commit -a "yuhao yuhao@20080808@qq.com" -m "v2" --change="EXPOSE 80 443" 8ddf4ce923ef new-nginx-image #将容器提交为一个本地镜像
[root@centos7 ~] docker pull nginx:1.20.2 #从镜像仓库下载镜像
[root@centos7 ~] docker push nginx:1.20.2 #从本地上传镜像到镜像仓库(需要登录认证)
[root@centos7 ~] docker history centos:7.9.2009 #查看的镜像的构建历史
[root@centos7 ~] docker load -i nginx-1.20.2.tar #从一个tar包或标准输入导入镜像
[root@centos7 ~] docker rmi -f 53ec353d8dc4 90a4cd9dfe4c #删除一个或多个镜像
[root@centos7 ~] docker save 50fe74b50e0d -o nginx-1.20.2.tar #保存一个或多个镜像到一个压缩文件(默认是标准输出)
[root@centos7 ~] docker tag nginx:1.20.2 harbor.haoge.com/myserver/nginx:1.20.2 #为镜像添加一个新的tag
[root@centos7 ~] docker login #登录镜像仓库
[root@centos7 ~] docker logout #登出镜像仓库
#基于容器制作镜像
[root@centos7 ~] docker run -it --name b1 busybox
[root@centos7 ~] docker commit -a "yuhao@qq.com" -c 'CMD /bin/httpd -fv -h /data/html' -c "EXPOSE 80" b1 httpd-busybox:v1.0
[root@centos7 ~] docker run -d -P --name httpd01 httpd-busybox:v1.0

b.docker容器相关操作命令

[root@centos7 ~] docker version #显示docker client和docker server的版本信息
[root@centos7 ~] docker info #显示系统信息
[root@centos7 ~] docker run -it centos:7.9.2009 
[root@centos7 ~] docker create -it --name test1 nginx:1.20.2 #创建一个新的容器且创建后的容器处于退出状态
[root@centos7 ~] docker inspect 50fe74b50e0d #显示docker对象(镜像、网络、容器等)的详细信息
[root@centos7 ~] docker cp 源 目的 #从容器和宿主机相互拷贝文件或目录
[root@centos7 ~] docker diff 8ddf4ce923ef #对比容器和镜像有差异的文件或目录
[root@centos7 ~] docker exec -it 40e6379cf371 sh/bash #进入到容器执行命令操作,推荐使用此方式
[root@centos7 ~] docker kill $(docker ps -a -q) 强制关闭所有运行中的容器
[root@centos7 ~] docker logs -f nginx-container-test1 #持续查看容器标准输出和错误输出的日志
[root@centos7 ~] docker port 81b344cff55d #列出一个容器端口映射关系
[root@centos7 ~] docker ps #列出容器,加上-a是列出包含为运行的所有容器
[root@centos7 ~] docker rename awesome_cerf nginx-container1 #重命名容器
[root@centos7 ~] docker restart ID/容器名称 #重启容器
[root@centos7 ~] docker rm -f 11445b3a84d3 #强制删除运行中的容器
[root@centos7 ~] docker rm -f `docker ps -aq -f status=exited` #批量删除已退出容器
[root@centos7 ~] docker rm -f $(docker ps -a -q) #批量删除所有容器
[root@centos7 ~] docker run -it docker.io/centos bash #创建并进入容器,ctrl+p+q退出容器不注销
[root@centos7 ~] docker run -it --name nginx-test1 nginx:1.20.2 #自定义容器名称
[root@centos7 ~] docker run -it --name -m 256m nginx-test1 nginx:1.20.2 #限制内存
[root@centos7 ~] docker run -it --rm --name stress --cpus 2 --cpuset-cpus 1,3 lorel/docker-stress-ng --cpu 4 --vm 4 #限制CPU并绑定
[root@centos7 ~] docker run -p 80:80/tcp -p 443:443/tcp --name nginx nginx:1.20.2 #创建容器并指定多端口映射
[root@centos7 ~] docker run -d -p 80:80 --name nginx-container-test1 nginx:1.20.2 #后台运行容器
[root@centos7 ~] docker run -it --rm --name nginx-delete-test nginx:1.20.2 bash #单次运行容器
[root@centos7 ~] docker run -it -d centos:7.9.2009 /usr/bin/tail -f '/etc/hosts' #创建容器的时候传递命令及参数
[root@centos7 ~] docker start ID/容器名称 #启动一个或多个容器
[root@centos7 ~] docker stats #显示容器资源的实时统计信息
[root@centos7 ~] docker stop ID/容器名称 #停止一个或多个容器
[root@centos7 ~] docker update 容器 --cpus 2 #更新容器配置信息,比如资源限制的值

五、Docker 镜像管理

a.Docker镜像简介

  • docker镜像基于union file system将多个目录合并挂载至一个目录给容器使用
  • docker镜像只有rootfs而没有内核、运行使用的是宿主机的bootfs
    • rootfs(root file system),文件系统
    • bootfs(boot file system),主要包含 bootloader 和 Kernel
  • 一个镜像是有一层或者多层合并而成,每一层称为是一个layer
  • 镜像可以基于其它镜像进行重新构建,被引用的镜像称为父镜像
  • 一个镜像可以同时被创建为多个容器
  • 镜像是只读的,在容器的任何更改都不会直接修改镜像

镜像即创建容器的模版,含有启动容器所需要的文件系统及所需要的内容,因此镜像主要用于方便和快速的创建并启动容器

b. Dockerfile简介

Dockerfile 可以理解为构建docker 镜像的源码。docker 可以通过读取一个dockerfile来自动构建docker image ,Dockerfile是一个文本文件,其中包含了按顺序排列的构建指定镜像所需要的全部命令, Dockerfile可以放在任意路径,但文件名必须为Dockerfile,且首字母D必须大写。使用Dockerfile构建镜像可以实现镜像的自动化构建,提高部署速度和环境的一致性。

c. Dockerfile 指令

Dockerfile格式要求

  • #号开头的行为注释行
  • 可以设置.dockeringore指定不打包进镜像的文件列表
  • docker build 中执行的shell命令是由基础镜像所包含的命令集合
  • 指令不区分大小写,一般默认都写成大写
  • 第一个非注释行,必须是“FROM”指令,指出基于哪个基础镜像

常用的Dockerfile指令及说明

指令 说明
FROM 设置镜像使用的基础镜像
MAINTAINER 设置镜像的作者信息,已被淘汰,建议使用LABEL标签代替
RUN 编译镜像时运行的脚本
CMD 设置容器的启动命令
LABEL 设置镜像的标签
EXPOESE 设置镜像暴露的端口
ENV 设置容器的环境变量
ADD 编译镜像时复制文件到镜像中
COPY 编译镜像时复制文件到镜像中
ENTRYPOINT 设置容器的入口程序
VOLUME 设置容器的挂载卷
USER 设置运行RUN CMD ENTRYPOINT的用户名
WORKDIR 设置RUN CMD ENTRYPOINT COPY ADD指令的工作目录,类似cd命令
ARG 设置编译镜像时加入的参数
ONBUILD 设置镜像的ONBUILD指令

d. Dockerfile 相关指令详解

1、FROM: 指定基础镜像

FROM指令是最重要的一个并且必须为Dockerfile文件开篇的第一个非注释行,用于为镜像文件构建过程中指定基准镜像,后续的指令运行于此基础镜像所提供的运行环境。 基准镜像可以是任何可用的镜像文件,默认情况下,docker build时候会在docker主机上查找指定的镜像,在其不存在时,则会从Docker Hub Registry上拉取所需的镜像文件,如果找不到指定的镜像文件,docker build 会返回一个错误信息

如何选择合适的镜像

对于不同的软件官方都提供了相关的docker镜像,比如: nginx、redis、mysql、httpd、tomcat、jdk等服务类的镜像,也有操作系统类,如: centos、ubuntu、debian等。建议使用官方镜像,比较安全。

格式:

FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
#说明: 
--platform 指定镜像的平台,比如: linux/amd64, linux/arm64, or windows/amd64
tag 和 digest是可选项,如果不指定,默认为latest

示例:

FROM scratch #所有镜像的起源镜像,相当于ObjectFROM ubuntu
FROM ubuntu:bionic
FROM centos:2009

2、LABEL: 指定镜像元数据

可以给镜像添加标签,来帮助项目组织镜像、记录许可信息、帮助自动化等。对于每个标签,添加一行以LABEL开头并带有一个或多个键值对的行

注意:

  1. 如果字符串中包含空格,则必须用双引号引起来或转义这个空格。如果字符串中包含双引号,必须转义
  2. 一个镜像可以有多个标签

格式:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

示例:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL "org.label-schema.name": "CentOS Base Image"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
#一行格式
LABEL multi.label1="value1" multi.label2="value2" other="value3"
#多行格式
LABEL multi.label1="value1" \
    multi.label2="value2" \
    other="value3"

docker inspect 命令可以查看LABEL

3、MAINTAINER: 指定维护者信息

此指令已过时,用LABEL代替

格式:

MAINTAINER <name>

示例:

MAINTAINER yuhao@20080808@qq.com
#用LABEL代替
LABEL maintainer="yuhao@20080808@qq.com"

4、RUN: 执行 shell命令

RUN 指令用来在构建镜像阶段需要执行 FROM 指定镜像所支持的Shell命令。
注意: RUN 可以写多个,每一个RUN指令都会建立一个镜像层,所以尽可能合并成一条指令,比如将多个shell命令通过 && 连接一起成为在一条指令
每个RUN都是独立运行的,和前一个RUN无关

格式:

#shell 格式: 相当于 /bin/sh -c <命令> 此种形式支持环境变量
RUN <命令>
#exec 格式: 此种形式不支持环境变量,注意:是双引号,不能是单引号
RUN ["executable","param1","param2"...]
#exec格式可以指定其它shell
RUN ["/bin/bash","-c","echo hello world"]

示例:

RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
RUN ["/bin/bash", "-c", "echo hello world"]
RUN yum -y install epel-release \
  && yum -y install nginx \
  && rm -rf /usr/share/nginx/html/*
  && echo "<h1> docker test nginx </h1>" > /usr/share/nginx/html/index.html

多个 前后RUN 命令独立无关和shell命令不同

#world.txt并不存放在/app内
RUN cd /app
RUN echo "hello" > world.txt

5、ENV: 设置环境变量

ENV 可以定义环境变量和值,会被后续指令(如:ENV,ADD,COPY,RUN等)通过$KEY或${KEY}进行引用,并在容器运行时保持

格式:

#变量赋值格式1
ENV <key> <value>       #此格式只能对一个key赋值,<key>之后的所有内容均会被视作其<value>的组成部分

#变量赋值格式2
ENV <key1>=<value1> <key2>=<value2> \  
<key3>=<value3> ...     #此格式可以支持多个key赋值,定义多个变量建议使用

#如果<value>中包含空格,可以以反斜线\进行转义,也可通过对<value>加引号进行标识;另外,反斜线也可用于续行
#只使用一次变量
RUN <key>=<value> <command>

#引用变量
RUN $key .....
#变量支持高级赋值格式
${key:-word} # 如果key变量值为空,返回word字符串
${key:+word} # 如果key变量为空,什么都不做,否则word返回

如果运行容器时如果需要修改变量,可以执行下面通过基于 exec 机制实现
注意: 下面方式只影响容器运行时环境,而不影响构建镜像的过程,即只能覆盖docker run时的环境变量,而不会影响docker build时环境变量的值

docker run -e|--env <key>=<value>
#说明
-e, --env list  #Set environment variables
  --env-file filename   #Read in a file of environment variables

示例:

#格式1
ENV myName="John Doe" myDog=Rex\ The\ Dog \
  myCat=fluffy

#格式2
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy

6、COPY: 复制文件至容器内

复制本地宿主机的文件到容器中的

格式:

COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"] #路径中有空白字符时,建议使用此格式

说明:

  • 可以是多个,可以使用通配符
  • 必须是build上下文中的路径(为 Dockerfile 所在目录的相对路径),不能是其父目录中的文件
  • 如果是目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制
  • 如果指定了多个, 或在中使用了通配符,则必须是一个目 录,且必须以 / 结尾
  • 可以是绝对路径或者是 WORKDIR 指定的相对路径
  • 使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等
  • 如果事先不存在,它将会被自动创建,这包括其父目录路径,即递归创建目录

示例:

COPY hom* /mydir/  
COPY hom?.txt /mydir/

7、ADD: 复制和解包文件

该命令可认为是增强版的COPY,不仅支持COPY,还支持自动解压缩。可以将文件复制指定的到容器中

格式:

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

说明:

  • 可以是Dockerfile所在目录的一个相对路径;也可是一个 URL;还可是一个 tar 文件(自动解压)
  • 可以是绝对路径或者是 WORKDIR 指定的相对路径
  • 如果是目录,只复制目录中的内容,而非目录本身
  • 如果是一个 URL ,下载后的文件权限自动设置为 600
  • 如果为URL且不以/结尾,则指定的文件将被下载并直接被创建为,如果以 / 结尾,则文件名URL指定的文件将被直接下载并保存为/< filename>
  • 如果是一个本地文件系统上的打包文件,如: gz, bz2 ,xz ,它将被解包 ,其行为类似于”tar -x”命令,但是通过URL获取到的tar文件将不会自动展开
  • 如果有多个,或其间接或直接使用了通配符,则必须是一个以/结尾的目录路径;如果不以/结尾,则其被视作一个普通文件,的内容将被直接写入到

示例:

ADD test relativeDir/      # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/     # adds "test" to /absoluteDir/
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /

8、 CMD: 容器启动命令

一个容器中需要持续运行的进程一般只有一个,CMD 用来指定启动容器时默认执行的一个命令,且其运行结束后,容器也会停止,所以一般CMD 指定的命令为持续运行且为前台命令

说明:

  • 如果docker run没有指定任何的执行命令或者Dockerfile里面也没有ENTRYPOINT命令,那么开启容器时就会使用执行CMD指定的默认的命令
  • 前面的 RUN 命令是在构建镜像时执行的命令,注意二者的不同之处
  • 每个 Dockerfile 只能有一条 CMD 命令。如指定了多条,只有最后一条被执行
  • 如果用户启动容器时用 docker run xxx 指定运行的命令,则会覆盖 CMD 指定的命令

格式:

# 使用 exec 执行,推荐方式,第一个参数必须是命令的全路径,此种形式不支持环境变量
CMD ["executable","param1","param2"]

# 在 /bin/sh 中执行,提供给需要交互的应用;此种形式支持环境变量
CMD command param1 param2

# 提供给 ENTRYPOINT 命令的默认参数
CMD ["param1","param2"]

示例:

CMD ["nginx", "-g", "daemon off;"]
CMD ["/bin/sh","-c","/opt/start.sh"]

9、ENTRYPOINT: 入口点

功能类似于CMD,配置容器启动后执行的命令及参数

格式:

# 使用 exec 执行
ENTRYPOINT ["executable", "param1", "param2"...]

# shell中执行
ENTRYPOINT command param1 param2

说明:

  • ENTRYPOINT 不能被 docker run 提供的参数覆盖,而是追加,即如果docker run 命令有参数,那么参数全部都会作为ENTRYPOINT的参数
  • 如果docker run 后面没有额外参数,但是dockerfile中有CMD命令(即上面CMD的第三种用法),即Dockerfile中即有CMD也有ENTRYPOINT,那么CMD的全部内容会作为ENTRYPOINT的参数
  • 如果docker run 后面有额外参数,同时Dockerfile中即有CMD也有ENTRYPOINT,那么docker run后面的参数覆盖掉CMD参数内容,最终作为ENTRYPOINT的参数
  • 可以通过docker run –entrypoint string 参数在运行时替换,注意string不要加空格
  • 使用CMD要在运行时重新写命令本身,然后在后面才能追加运行参数,ENTRYPOINT则可以运行时无需重写命令就可以直接接受新参数
  • 每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个生效
  • 通常会利用ENTRYPOINT指令配合脚本,可以为CMD指令提供环境配置

示例1:

FROM centos:centos7.9-v10.0
LABEL maintainer="yuhao@20080808@qq.com"
ENV version=1.18.0
ADD nginx-$version.tar.gz /usr/local/
RUN cd /usr/local/nginx-$version && ./configure --prefix=/apps/nginx && make &&
make install && rm -rf /usr/local/nginx* && sed -i 's/.*nobody.*/user nginx;/'
/apps/nginx/conf/nginx.conf && useradd -r nginx
COPY index.html /apps/nginx/html
VOLUME ["/apps/nginx/html"]
EXPOSE 80 443
CMD ["-g","daemon off;"]
ENTRYPOINT ["/apps/nginx/sbin/nginx"]
#上面两条指令相当于ENTRYPOINT ["/apps/nginx/sbin/nginx","-g","daemon off;"]

示例2:

利用脚本实现指定环境变量动态生成配置文件内容

# 编辑Dockerfile文件,内容如下
[root@centos7 ~]#cat Dockerfile
FROM nginx:1.16-alpine
LABEL maintainer="yuhao@20080808@qq.com"
ENV DOC_ROOT='/data/website/'
ADD index.html ${DOC_ROOT}
ADD entrypoint.sh /bin/
EXPOSE 80/tcp 8080
#HEALTHCHECK --start-period=3s CMD wget -0 - -q http://${IP:-0.0.0.0}:
{PORT:-80}/
CMD ["/usr/sbin/nginx","-g", "daemon off;"]  #CMD指令的内容都成为了ENTRYPOINT的参数
ENTRYPOINT [ "/bin/entrypoint.sh"]

#编辑entrypoint.sh脚本文件
[root@centos7 ~]#cat entrypoint.sh
#!/bin/sh
cat > /etc/nginx/conf.d/www.conf <<EOF
server {
 server_name ${HOSTNAME};
 listen ${IP:-0.0.0.0}:${PORT:-80};
 root  ${DOC_ROOT:-/usr/share/nginx/html};
}
EOF
exec "$@"

## 构建镜像
[root@centos7 ~]# chmod +x entrypoint.sh
[root@centos7 ~]# docker build -t nginx:v1.0 .
[root@centos7 ~]# docker run --name n1 --rm -P -e "PORT=8080" -e "HOSTNAME=www.yuhao.org" nginx:v1.0

10、ARG: 构建参数

ARG指令在build 阶段指定变量,和ENV不同的是,容器运行时不会存在这些环境变量

格式:

ARG <name>[=<default value>]

说明:

  • 如果和ENV同名,ENV覆盖ARG变量
  • 可以用 docker build –build-arg <参数名>=<值> 来覆盖

示例:

FROM busybox
ARG author="yuhao@20080808@qq.com"
LABEL maintainer="${author}"

11、VOLUME: 匿名卷

在容器中创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等,默认会将宿主机上的目录挂载至VOLUME 指令指定的容器目录。即使容器后期被删除,此宿主机的目录仍会保留,从而实现容器数据的持久保存。而匿名卷则是由Docker自动生成的,并且没有自定义名字,只能通过自动分配的ID进行引用。匿名卷在容器删除时会被自动删除

为了保留数据,可以使用命名卷代替匿名卷。

docker run -v my_volume:/path/in/container my_image

匿名卷格式:

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

注意:
<容器内路径>如果在容器内不存在,在创建容器时会自动创建
<容器内路径>如果是存在的,同时目录内有内容,将会把此目录的内容复制到宿主机的实际目录

注意:

  • Dockerfile中的VOLUME实现的是匿名数据卷,无法指定宿主机路径和容器目录的挂载关系
  • 通过docker rm -fv <容器ID> 可以删除容器的同时删除VOLUME指定的卷

示例:

[root@centos7 ~]#cat Dockerfile
FROM alpine
LABEL maintainer="yuhao20080808@qq.com"
COPY repositories /etc/apk/repositories
VOLUME [ "/test1","/test2" ]

12、 EXPOSE: 暴露端口

指定服务端的容器需要对外暴露(监听)的端口号,以实现容器与外部通信。EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会真正暴露端口,即不会自动在宿主进行端口映射。因此,在启动容器时需要通过 -P 或 -p ,Docker 主机才会真正分配一个端口转发到指定暴露的端口才可使用

注意: 即使 Dockerfile 没有 EXPOSE 端口指令,也可以通过docker run -p 临时暴露容器内程序真正监听的端口,所以EXPOSE 相当于指定默认的暴露端口,可以通过docker run -P 进行真正暴露

格式:

EXPOSE <port>[/ <protocol>] [<port>[/ <protocol>] ..]

#说明
<protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议

示例:

[root@centos7 dockerfile]# echo Website in Dockerfile > index.html

[root@centos7 dockerfile]# vim Dockerfile
FROM busybox
LABEL maintainer="yuhao20080808@qq.com"
COPY index.html /data/website/
EXPOSE 80

[root@centos7 dockerfile]# docker build -t test:v1 .
[root@centos7 dockerfile]# docker run --rm -P --name test1 test:v1 /bin/httpd -f -h /data/website

13、WORKDIR: 指定工作目录

为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录,当容器运行后,进入容器内WORKDIR指定的默认目录

WORKDIR 指定工作目录(或称当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会自行创建,相当于创建一个目录然后cd到了创建的目录

格式:

WORKDIR /path/to/workdir

示例:

#如果想实现相同目录可以使用WORKDIR
WORKDIR /app
RUN echo "hello" > world.txt

可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
#则最终路径为 /a/b/c

14、USER: 指定当前用户

指定运行容器的用户名或 UID,在后续dockerfile中的 RUN ,CMD和ENTRYPOINT指令时使用此用户
当服务不需要管理员权限时,可以通过该命令指定运行用户
这个用户必须是事先建立好的,否则无法切换。如果没有指定 USER,默认是 root 身份执行

格式:

USER <user>[:<group>]
USER <UID>[:<GID>]

示例:

RUN useradd loan -u 1911 
RUN groupadd -r mysql && useradd -r -g mysql mysql
USER mysql

15、HEALTHCHECK: 健康检查

检查容器的健康性

格式:

HEALTHCHECK [选项] CMD <命令> #设置检查容器健康状况的命令,如果命令执行失败,则返回1,即
unhealthy
HEALTHCHECK NONE #如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK 支持下列选项: 
--interval=<间隔>  #两次健康检查的间隔,默认为 30 秒
--timeout=<时长>   #健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默30 秒
--retries=<次数>   #当连续失败指定次数后,则将容器状态视为 unhealthy,默认3次
--start-period=<FDURATION> #default: 0s
#检查结果返回值:
0  #success  the container is healthy and ready for use
1  #unhealthy  the container is not working correctly
2  #reserved  do not use this exit code

示例:

FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/

e. Dockerfile 缓存机制

Dockerfile的缓存机制是指Docker在构建镜像时会缓存之前处理过的层(layer)以提高构建效率。具体地说,每条Dockerfile指令都会生成一个层(layer),并只有在这个层发生改变时才会重新运行该指令。因此,如果构建过程中某些指令没有改变,则Docker会直接使用之前生成的缓存层,从而加速构建过程。这种缓存机制对于频繁构建、频繁调试的场景尤其有用,它可以避免重复地执行较慢的构建命令,从而节省时间和资源。

注意:Dockerfile的缓存机制只是适用于构建过程中的单个镜像,对于多个镜像之间的依赖关系无法处理。如果多个镜像之间存在依赖关系,则需要手动保证每个镜像都重新构建以确保依赖关系正确。为了进一步减小缓存失效的影响,可以将经常变化的指令往后放置,将不变的指令往前放置,以提高重用率。

f、构建镜像docker build 命令

docker build命令使用Dockerfile文件创建镜像

命令格式:

docker build [OPTIONS] PATH | URL | -
说明: 
PATH | URL | -   #可以使是本地路径,也可以是URL路径。若设置为 - ,则从标准输入获取Dockerfile的内容

-f, --file string  #Dockerfile文件名,默认为 PATH/Dockerfile
--force-rm  #总是删除中间层容器,创建镜像失败时,删除临时容器
--no-cache  #不使用之前构建中创建的缓存
-q  --quiet=false  #不显示Dockerfile的RUN运行的输出结果
--rm=true  #创建镜像成功时,删除临时容器
-t --tag list  #设置注册名称、镜像名称、标签。格式为 <注册名称>/<镜像名称>:<标签>(标签默认为latest)

示例:

docker build .  #构建出REPOSITORY和TAG都为<none>的镜像
docker build /usr/local/src/nginx   #指定Dockerfile路径的方式
docker build -f /path/to/a/Dockerfile . # 指定Dockerfile绝对路径
docker build -t test/myapp . #默认标签为latest
docker build -t test/myapp:1.0.1 . #指定单个标签
docker build -t test/myapp:1.0.2 -t shykes/myapp:latest .  #为同一个镜像创建两个标签

g、Dockerfile 制作基于基础镜像的Base镜像

准备目录结构,下载镜像并初始化系统

#按照业务类型或系统类型等方式划分创建目录环境,方便后期镜像比较多的时候进行分类
[root@ubuntu1804 ~]#mkdir /data/dockerfile/{web/{nginx,jdk},system/{centos,ubuntu}} -p

[root@ubuntu1804 ~]#tree /data/dockerfile/
/data/dockerfile/
├── system
│  ├── centos
│  └── ubuntu
└── web
 ├── jdk
 ├── nginx

#下载基础镜像
[root@ubuntu1804 ~]#docker pull centos:centos7.9.2009

#先制作基于基础镜像的系统base镜像
[root@ubuntu1804 ~]#cd /data/dockerfile/system/centos/
[root@ubuntu1804 centos]#vim Dockerfile
FROM centos:centos7.9.2009
LABEL maintainer="yuhao20080808@qq.com"
RUN yum -y install wget && rm -f /etc/yum.repos.d/* &&  \
wget -P /etc/yum.repos.d/ http://mirrors.aliyun.com/repo/Centos-7.repo \
&& wget -P /etc/yum.repos.d/ http://mirrors.aliyun.com/repo/epel-7.repo \
&& sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/Centos-7.repo \
&& yum -y install vim-enhanced tcpdump lrzsz tree telnet bash-completion net-tools wget curl bzip2 lsof zip unzip nfs-utils gcc make gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel zlib-devel \
&& yum clean all \
&& rm -f /etc/localtime \
&& ln -s ../usr/share/zoneinfo/Asia/Shanghai /etc/localtime

[root@ubuntu1804 centos]# docker build -t centos7-base:v1 .
[root@ubuntu1804 centos]# docker images
REPOSITORY                            TAG              IMAGE ID       CREATED          SIZE
centos7-base                          v1               19deb727d5c7   21 seconds ago   433MB
centos                                centos7.9.2009   eeb6ee3f44bd   20 months ago    204MB

六、Docker 容器数据管理

a.Docker数据管理分层目录

正在运行中的容器如果生成了新的数据或者修改了现有的一个已经存在的文件内容,那么新产生的数据将会被复制到读写层进行持久化保存,这个读写层也就是容器的工作目录,此即“写时复制(COW) copy on write”机制。

通过 docker inspect 命令可以看到数据的各个层级, 各层作用如下:

  • Lower Dir:image镜像层(镜像本身,只读)

  • Upper Dir:容器的上层(读写)

  • Merged Dir:容器的文件系统,使用Union FS(联合文件系统)将lowerdir和upper Dir:合并给容器使用。

  • Work Dir:容器在 宿主机的工作目录

Docker的镜像是分层设计的,镜像层是只读的,通过镜像启动的容器添加了一层可读写的文件系统,用户写入的数据都保存在这一层当中。

b.容器数据持久保存方式

如果要将写入到容器的数据永久保存,则需要将容器中的数据保存到宿主机的指定目录,目前Docker的数据类型分为两种:

  • 一是数据卷(data volume),数据卷实际上就是宿主机上的目录或者是文件,可以被直接mount到容器当中作为容器的本地文件系统使用,基于数据卷通过将宿主机的文件或目录挂载到容器的指定目录,当容器中的挂载目录产生的新数据即可间接的保存到宿主机以实现持久化的目的
  • 二是数据卷容器(Data volume container), 数据卷容器是将宿主机的目录挂载至一个专用的数据卷容器,然后让其他容器通过数据卷容器继承挂载的目录或文件,以实现将新产生的数据持久化到宿主机的目的。

c.Docker创建数据卷volume

docker run 命令的以下格式可以实现数据卷

-v, --volume=[host-src:]container-dest[:<options>]
<options>
ro 从容器内对此数据卷是只读,不写此项默认为可读可写
rw 从容器内对此数据卷可读可写,此为默认值

数据卷容器示例:

# 创建数据卷
[root@centos7 ~]# docker volume create nginx-data
[root@centos7 ~]# docker volume ls
DRIVER VOLUME NAME
local nginx-data
启动容器并挂载至本地数据卷
[root@centos7 ~]# docker run -it -d -p 80:80 -v nginx-data:/data nginx:1.23.2
4445e4640c74e1c503a7f8c704270abd58c5bc70aacf600e39945f7fd74ac810
进入容器,并创建index.html文件
[root@centos7 ~]# docker exec -it 4445e4640c74 bash
root@4445e4640c74:/# echo "nginx web" > /data/index.html
root@4445e4640c74:/# exit
在宿主机上可以看到文件被创建出来
# ls /var/lib/docker/volumes/nginx-data/_data/index.html
/var/lib/docker/volumes/nginx-data/_data/index.html

d.Docker 数据目录挂载

1、宿主机创建目录
[root@centos7 ~]# mkdir /data/testapp –p
2、宿主机创建文件
[root@centos7 ~]# echo "testapp web page" > /data/testapp/index.html
3、启动第一个Nginx容器
[root@centos7 ~]# docker run -d --name web1 -v /data/testapp:/usr/share/nginx/html/testapp -p 80:80 nginx:1.23.2
4、启动第二个Nginx容器
[root@centos7 ~]# docker run -d --name web2 -v /data/testapp:/usr/share/nginx/html/testapp:ro -p 81:80 nginx:1.23.2
5、可以通过浏览器访问者两个容器服务:http://IP:80/testapp,http://IP:81/testapp,会看到两个服务的页面显示内容完全一致

e.Docker 数据目录及配置多卷挂载

nginx多卷挂载:
1、创建Nginx目录
[root@centos7 ~]# mkdir /data/nginx/conf -p
2、复制刚创建的web1容器内的nginx配置至宿主机目录下
[root@centos7 ~]# docker cp web1:/etc/nginx/nginx.conf /data/nginx/conf/
3、运行第三个Nginx容器,可以看到可以同时挂载多个数据卷
[root@centos7 ~]# docker run -d --name web3 -v /data/testapp:/usr/share/nginx/html/testapp -v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro -p 83:80 nginx:1.23.2
mysql容器示例:
[root@centos7 ~]# docker pull mysql:5.7.38
[root@centos7 ~]# docker run -it -d -p 3306:3306 -v /data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.38

f.Docker 数据管理-删除容器

创建容器的时候指定参数会删除/var/lib/docker/containers/的容器数据目录,但是不会删除数据卷的内容,如下

# docker rm -f web3
# ls /data/testapp/index.html
/data/testapp/index.html #挂载的数据卷不会被删除

g.数据卷的特点及使用场景

  • 数据卷的特点
    • 数据卷是宿主机的目录或者文件,并且可以在多个容器之间共同使用。
    • 在宿主机对数据卷更改数据后会在所有容器里面会立即更新。
    • 数据卷的数据可以持久保存,即使删除使用使用该容器卷的容器也不影响。
    • 在容器里面的写入数据不会影响到镜像本身,即数据卷的变化不会影响镜像的更新
    • 依赖于宿主机目录,宿主机出问题,上面容器会受影响,当宿主机较多时,不方便统一管理
  • 数据卷使用场景
    • 容器数据持久化(mysql数据、nginx日志等类型)
    • 静态web页面挂载
    • 应用配置文件挂载
    • 多容器间的目录或文件共享

h.关于匿名数据卷和命名数据卷

命名卷就是有名字的卷,使用 docker volume create <卷名> 形式创建并命名的卷;而匿名卷就是没名字的卷,一般是 docker run -v /data 这种不指定卷名的时候所产生,或者 Dockerfile 里面的定义直接使用的。

有名字的卷,在用过一次后,以后挂载容器的时候还可以使用,因为有名字可以指定。所以一般需要保存的数据使用命名卷保存。而匿名卷则是随着容器建立而建立,随着容器消亡而淹没于卷列表中(对于 docker run 匿名卷不会被自动删除)。 因此匿名卷只存放无关紧要的临时数据,随着容器消亡,这些数据将失去存在的意义。
Dockerfile中指定VOLUME为匿名数据卷,其目的只是为了将某个路径确定为卷。

按照最佳实践的要求,不应该在容器存储层内进行数据写入操作,所有写入应该使用卷。如果定制镜像的时候,就可以确定某些目录会发生频繁大量的读写操作,那么为了避免在运行时由于用户疏忽而忘记指定卷,导致容器发生存储层写入的问题,就可以在 Dockerfile 中使用 VOLUME 来指定某些目录为匿名卷。这样即使用户忘记了指定卷,也不会产生不良的后果。这个设置可以在运行时覆盖。通过 docker run 的 -v 参数或者 docker-compose.yml 的 volumes指定。使用命名卷的好处是可以复用,其它容器可以通过这个命名数据卷的名字来指定挂载,共享其内容(不
过要注意并发访问的竞争问题)。

比如,Dockerfile 中说 VOLUME /data,那么如果直接 docker run,其 /data 就会被挂载为匿名卷,向 /data 写入的操作不会写入到容器存储层,而是写入到了匿名卷中。但是如果运行时 docker run -v mydata:/data,这就覆盖了 /data 的挂载设置,要求将 /data 挂载到名为 mydata 的命名卷中。
所以说 Dockerfile 中的 VOLUME 实际上是一层保险,确保镜像运行可以更好的遵循最佳实践,不向容器存储层内进行写入操作。

七、Docker 网络管理

a.Docker容器的网络模式

Docker 的网络支持5种网络模式

  • none : 把容器放入独立的网络空间但不做任何网络配置
  • bridge (默认): 使用 Linux 网桥和 iptables 提供容器互联,Docker 在每台主机上创建一个名叫 docker0的网桥,通过 veth pair 来连接该主机的每一个 EndPoint
  • host: 使用主机网络名空间,复用主机网络
  • container: 重用其他容器的网络
  • network-name: 自定义网络名称

查看默认网络模式示例:

[root@centos7 ~]#  docker network ls

创建容器时候网络模式指定:

docker run --network <mode>
docker run --net=<mode>
<mode>: 可是以下值
none
bridge
host
container:<容器名或容器ID>
<自定义网络名称>

b.bridge模式

bridge模式是docker的默认模式,也是使用比较多的模式,此模式创建的容器会为每一个容器分配自己的网络 IP 等信息,并将容器连接到一个虚拟网桥(docker0)与外界通信

可以和外部网络之间进行通信,通过SNAT访问外网,使用DNAT可以让容器被外部主机访问,所以此模式也称为NAT模式

此模式宿主机需要启动ip_forward功能

vim /etc/sysctl.conf
net.ipv4.ip_forward = 1 

使配置生效: sysctl -p

# 一般默认装好docker并启动后即开启了ip_forward
cat /proc/sys/net/ipv4/ip_forward

bridge模式特点

  • 网络资源隔离: 不同宿主机的容器无法直接通信,各自使用独立网络
  • 无需手动配置: 容器默认自动获取172.17.0.0/16的IP地址,此地址可以修改
  • 可访问外网: 利用宿主机的物理网卡,SNAT连接外网
  • 外部主机无法直接访问容器: 可以通过配置DNAT接受外网的访问
  • 低性能较低: 因为可通过NAT,网络转换带来更的损耗

查看bridge模式信息

[root@ubuntu1804 ~]# docker network inspect bridge

修改桥接地址方法

# 方法一:
[root@ubuntu1804 ~]# vim /lib/systemd/system/docker.service
xecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.100.0.1/24

systemctl daemon-reload && systemctl restart docker
#方法二:
[root@ubuntu1804 ~]# vim /etc/docker/daemon.json
{
 "bip": "192.168.100.100/24",        #分配docker0网卡的IP,24是容器IP的netmask
 "default-gateway": "192.168.100.200",  #网关必须和bip在同一个网段
 "dns": [ "114.114.114.114", "8.8.8.8"]
}

[root@ubuntu1804 ~]# systemctl restart docker

c.host模式

​ 如果指定host模式启动的容器,那么新创建的容器不会创建自己的虚拟网卡,而是直接使用宿主机的网卡和IP地址,因此在容器里面查看到的IP信息就是宿主机的信息,访问容器的时候直接使用宿主机IP+容器端口即可,不过容器内除网络以外的其它资源,如: 文件系统、系统进程等仍然和宿主机保持隔离

​ 此模式由于直接使用宿主机的网络无需转换,性能最高,但是各容器内使用的端口不能相同,适用于运行容器端口比较固定的业务

Host 网络模式特点:

  • 共享宿主机网络
  • 网络性能无损耗
  • 网络故障排除相对简单
  • 各容器网络无隔离
  • 网络资源无法分别统计
  • 端口管理困难: 容易产生端口冲突
  • 不支持端口映射

示例:

docker run -d --network host --name nginx nginx:1.20.2
# 通过外部浏览器即可直接访问宿主机地址+端口

d.none模式

在使用none 模式后,Docker 容器不会进行任何网络配置,没有网卡、没有IP也没有路由,因此默认无法与外界通信,需要手动添加网卡配置IP等,所以极少使用

none模式特点

  • 使用参数 –network none 指定
  • 默认无网络功能,无法和外部通信
  • 无法实现端口映射
  • 适用于测试环境

e.container模式

使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,新创建的容器不会创建自己的网卡也不会配置自己的IP,而是和一个被指定的已经存在的容器共享IP和端口范围,因此这个容器的端口不能和被指定容器的端口冲突,除了网络之外的文件系统、进程信息等仍然保持相互隔离,两个容器的进程可以通过lo网卡进行通信

Container 模式特点

  • 使用参数 –-network container:名称或ID 指定
  • 与宿主机网络空间隔离
  • 容器间共享网络空间
  • 适合频繁的容器间的网络通信
  • 直接使用对方的网络,较少使用

示例:

#创建第一个容器:
docker run -it --name server1 -p 80:80 alpine:3.11 sh
#在同一节点的另一个终端执行下面操作
#创建第二个容器,基于第一个容器的container的网络模式
docker run -d --name server2 --network container:server1 nginx:1.20.2

f.自定义网络模式

自定义网络,可使用自定义的网段地址,网关等信息

可以使用自定义网络模式,实现不同集群应用的独立网络管理,而互不影响,而且在网一个网络内,可以直接利用容器名相互访问

自定义网络相关命令

[root@ubuntu1804 ~]#docker network --help
Usage: docker network COMMAND
Manage networks
    Commands:
    connect   Connect a container to a network
    create   Create a network
    disconnect Disconnect a container from a network
    inspect   Display detailed information on one or more networks
     ls     List networks
    prune    Remove all unused networks
     rm     Remove one or more networks
# 创建自定义网络:
docker network create -d <mode> --subnet <CIDR> --gateway <网关> <自定义网络名称>
#注意mode不支持host和none,默认是bridge模式

#引用自定义网络
docker run --network <自定义网络名称> <镜像名称>

# 删除自定义网络,默认三个网络无法删除
doccker network rm <自定义网络名称或网络ID>

示例:

1、创建自定义网络
[root@ubuntu1804 ~]# docker network create -d bridge --subnet 172.27.0.0/16 --gateway 172.27.0.1 test-net
[root@ubuntu1804 ~]# docker network ls
[root@ubuntu1804 ~]# brctl show  ## brctl命令需安装bridge-utils命令

2、利用自定义网络创建容器
[root@ubuntu1804 ~]# docker run -it --rm --network test-net alpine sh
/ # ip a

3、自定义网络容器间通信,可使用容器名进行通信
[root@ubuntu1804 ~]#docker run -it --rm --network test-net --name test1 alpine sh
/ # ip a

[root@ubuntu1804 ~]#docker run -it --rm --network test-net --name test2 alpine sh

此时在容器 test1 内即可直接通过test2的容器名访问test2容器

八、单机编排工具Docker Compose

a.docker-compose简介

宿主机启动较多的容器时,都是手动操作会觉得比较麻烦而且容易出错,此时推荐使用docker 单机编排工具 docker-compose

docker-compose 是 docker 容器的一种单机编排服务,docker-compose 是一个管理多个容器的工具,比如: 可以解决容器之间的依赖关系,并且可以替代docker命令对容器进行创建、启动和停止等手工的操作

docker命令相当于ansible命令,那么docker compose文件,就相当于ansible-playbook的yaml文件

docker-compose 项目是Docker 官方的开源项目,负责实现对Docker 容器集群的快速编排,docker-compose 将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)

github地址: https://github.com/docker/compose
官方地址: https://docs.docker.com/compose/

b.docker-compose在线安装

此方法安装的版本较旧,不推荐

#ubuntu安装,此为默认版本
[root@ubuntu1804 ~]#apt -y install docker-compose
[root@ubuntu1804 ~]#docker-compose --version

#CentOS7安装,依赖EPEL源
[root@centos7 ~]#yum -y install docker-compose
[root@centos7 ~]#docker-compose --version

c.docker-compose二进制安装

直接从github下载安装对应版本

参看说明: https://github.com/docker/compose/releases

# 直接下载比较慢,可使用国内代理站点进行下载,代理地址:https://ghproxy.com  在下载的资源前面加上这个地址即可
[root@centos7 ~]#  wget https://ghproxy.com/https://github.com/docker/compose/releases/download/v2.19.0/docker-compose-linux-x86_64
[root@centos7 ~]# mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose
[root@centos7 ~]# chmod +x /usr/local/bin/docker-compose
[root@centos7 ~]# docker-compose --help
# 或者使用curl命令下载
[root@centos7 ~]# curl -L https://ghproxy.com/https://github.com/docker/compose/releases/download/v2.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

d.docker-compose格式

1、docker-compose命令格式
docker-compose --help
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
#选项说明: 
-f,–file FILE #指定Compose 模板文件,默认为docker-compose.yml
-p,–project-name NAME #指定项目名称,默认将使用当前所在目录名称作为项目名。
--verbose  #显示更多输出信息
--log-level LEVEL   #定义日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi #不显示ANSI 控制字符
-v, --version #显示版本

#以下为命令选项,需要在docker-compose.yml|yaml 文件所在在目录里执行
config  -q #查看当前配置,没有错误不输出任何信息
up #创建并启动容器
build  #构建镜像
bundle #从当前docker compose 文件生成一个以<当前目录>为名称的json格式的Docker Bundle 备
份文件
create #创建服务
down #停止和删除所有容器、网络、镜像和卷
events #从容器接收实时事件,可以指定json 日志格式
exec #进入指定容器进行操作
help #显示帮助细信息
images #显示镜像信息
kill #强制终止运行中的容器
logs #查看容器的日志
pause #暂停服务
port #查看端口
ps #列出容器
pull #重新拉取镜像,镜像发生变化后,需要重新拉取镜像
push #上传镜像
restart #重启服务
rm #删除已经停止的服务
run #一次性运行容器
scale  #设置指定服务运行的容器个数
start #启动服务
stop #停止服务
top #显示容器运行状态
unpause #取消暂定
2、docker-compose文件格式

官方文档: https://docs.docker.com/compose/compose-file/

docker compose 文件是一个yaml格式的文件,所以注意行首的缩进很严格

默认docker-compose 命令会调用当前目录下的docker-compose.yml的文件,因此一般执行docker-compose命令前先进入docker-compose.yml文件所在目录

e.docker-compose使用

注意: 使用Docker compose之前,先要安装docker

docker compose 文件可在任意目录,创建文件名为docker-compose.yml 配置文件

wordpress示例:

[root@centos7 ~]# vim docker-compose.yml

version: '3'
services:
  db:
    image: mysql:8.0.29-oracle
    container_name: db
    restart: unless-stopped
    environment:
      - MYSQL_DATABASE=wordpress
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=123456
    volumes:
      - dbdata:/var/lib/mysql
    networks:
      - wordpress-network

  wordpress:
    depends_on:
      - db
    image: wordpress:php7.4-apache
    container_name: wordpress
    restart: unless-stopped
    ports:
      - "80:80"
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=123456
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress:/var/www/html
    networks:
      - wordpress-network

volumes:
  wordpress:
  dbdata:

networks:
  wordpress-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.0.0/16

[root@centos7 ~]# docker-compose up -d

mindoc示例:

version: "3"
services:
  mindoc:
    image: registry.cn-hangzhou.aliyuncs.com/mindoc-org/mindoc:v2.1
    container_name: mindoc
    privileged: false
    restart: always
    ports:
      - 8181:8181
    volumes:
      - /app/mindoc/data/conf://mindoc/conf
      - /app/mindoc/data/static://mindoc/static
      - /app/mindoc/data/views://mindoc/views
      - /app/mindoc/data/uploads://mindoc/uploads
      - /app/mindoc/data/runtime://mindoc/runtime
      - /app/mindoc/data/database://mindoc/database
    environment:
      - MINDOC_RUN_MODE=prod
      - MINDOC_DB_ADAPTER=sqlite3
      - MINDOC_DB_DATABASE=./database/mindoc.db
      - MINDOC_CACHE=true
      - MINDOC_CACHE_PROVIDER=file
      - MINDOC_ENABLE_EXPORT=false
      - MINDOC_BASE_URL=
      - MINDOC_CDN_IMG_URL=
      - MINDOC_CDN_CSS_URL=
      - MINDOC_CDN_JS_URL=
    dns:
      - 223.5.5.5
      - 223.6.6.6
[root@centos7 ~]# docker-compose up -d  

九、Docker 镜像仓库管理

a.镜像仓库介绍

Docker仓库,类似于yum仓库,是用来保存镜像的仓库。为了方便的管理和使用docker镜像,可以将镜像集中保存至Docker仓库中,将制作好的镜像push到仓库集中保存,在需要镜像时,从仓库中pull镜像即可。

公有云仓库: 由互联网公司对外公开的仓库

私有云仓库: 组织内部搭建的仓库,一般只为组织内部使用,常使用下面软件搭建仓库

  • docker registory
  • docker harbor

b.官方镜像仓库使用

1、需要登录注册

访问: https://hub.docker.com/ ,根据提示填写信息即可

2、客户端登录官方仓库

登录格式:

docker login [OPTIONS] [SERVER]
选项: 
-p, --password string  Password
  --password-stdin  Take the password from stdin
-u, --username string  Username

示例:

[root@centos7 ~]# docker login -u yuhao -pxxxxx docker.io
[root@centos7 ~]# docker login

3、给镜像打标签并上传至官方镜像

标签格式: docker.io/用户帐号/镜像名:TAG

docker tag nginx:1.23.1 docker.io/yuhao/nginx:1.23.1 
docker push docker.io/yuhao/nginx:1.23.1 
# 上传完成后可登录官网验证

4、此时其他人即可使用你上传至官网的镜像

c.私有云单机仓库Docker Registry

官方文档地址: https://docs.docker.com/registry/
官方github 地址: https://github.com/distribution/distribution
官方部署文档: https://github.com/docker/docs/blob/main/registry/deploying.md\

搭建Docker Registry并使用示例:

修改配置让docker login支持http协议
[root@centos7 ~]# vim /etc/docker/daemon.json
{
   "insecure-registries": ["192.168.100.51:5000"]
}
[root@centos7 ~]# systemctl restart docker
1、下载镜像
[root@centos7 ~]# docker pull registry:2.8.2
2、启动registry容器
[root@centos7 ~]# mkdir -p /data/myregistry
[root@centos7 ~]# docker run -d -p 5000:5000 -v /data/myregistry:/var/lib/registry --restart=always --name registry registry:2.8.2
3、本机使用registry仓库
[root@centos7 ~]# docker tag ubuntu:16.04 localhost:5000/my-ubuntu:16.04
[root@centos7 ~]# docker push localhost:5000/my-ubuntu:16.04
[root@centos7 ~]# docker image remove ubuntu:16.04
[root@centos7 ~]# docker image remove localhost:5000/my-ubuntu:16.04
[root@centos7 ~]# docker pull localhost:5000/my-ubuntu:16.04

d.Docker 之分布式仓库 Harbor简介

1、harbor介绍

Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,由VMware开源,其通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源 Docker Distribution。作为一个企业级私有Registry服务器,Harbor 提供了更好的性能和安全。提升用户使用Registry构建和运行环境传输镜像的效率。Harbor支持安装在多个Registry节点的镜像资源复制,镜像全部保存在私有 Registry 中,确保数据和知识产权在公司内部网络中管控,另外,Harbor也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等
harbor 官方github 地址: https://github.com/vmware/harbor
harbor 官方网址: https://goharbor.io/
harbor 官方文档: https://goharbor.io/docs/

2、harbor功能官方介绍

  • 基于角色的访问控制: 用户与Docker镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限
  • 镜像复制: 镜像可在多个Registry实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景
  • 图形化用户界面: 用户可以通过浏览器来浏览,检索当前Docker镜像仓库,管理项目和命名空间
  • AD/LDAP 支: Harbor可以集成企业内部已有的AD/LDAP,用于鉴权认证管理
  • 审计管理: 所有针对镜像仓库的操作都可以被记录追溯,用于审计管理
  • 国际化: 已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来
  • RESTful API: 提供给管理员对于Harbor更多的操控, 使得与其它管理软件集成变得更容易
  • 部署简单: 提供在线和离线两种安装工具, 也可以安装到vSphere平台(OVA方式)虚拟设备

3、harbor组成

  • Proxy: 对应启动组件nginx。它是一个nginx反向代理,代理Notary client(镜像认证)、Docker client(镜像上传下载等)和浏览器的访问请求(Core Service)给后端的各服务
  • UI(Core Service): 对应启动组件harbor-ui。底层数据存储使用mysql数据库,主要提供了四个子功能:
    • UI: 一个web管理页面ui
    • API: Harbor暴露的API服务
    • Auth: 用户认证服务,decode后的token中的用户信息在这里进行认证;auth后端可以接db、ldap、uaa三种认证实现
    • Token服务(上图中未体现): 负责根据用户在每个project中的role来为每一个docker push/pull命令发布一个token,如果从docker client发送给registry的请求没有带token,registry会重定向请求到token服务创建token
  • Registry: 对应启动组件registry。负责存储镜像文件,和处理镜像的pull/push命令。Harbor对镜像进行强制的访问控制,Registry会将客户端的每个pull、push请求转发到token服务来获取有效的token
  • Admin Service: 对应启动组件harbor-adminserver。是系统的配置管理中心附带检查存储用量,ui和jobserver启动时候需要加载adminserver的配置
  • Job Sevice: 对应启动组件harbor-jobservice。负责镜像复制工作的,他和registry通信,从一个registry pull镜像然后push到另一个registry,并记录job_log
  • Log Collector: 对应启动组件harbor-log。日志汇总组件,通过docker的log-driver把日志汇总到一起
  • DB: 对应启动组件harbor-db,负责存储project、 user、 role、replication、image_scan、access等的metadata数据

e.Harbor镜像仓库安装

下载地址: https://github.com/goharbor/harbor/releases

安装harbor示例:

前提条件:安装前需要先把docker和docker-compose安装完成
2、下载离线安装包
[root@centos7 ~]# mkdir /app  && cd /app
[root@centos7 app]# wget https://ghproxy.com/https://github.com/goharbor/harbor/releases/download/v2.8.2/harbor-offline-installer-v2.8.2.tgz
[root@centos7 app]# tar -zxvf harbor-offline-installer-v2.8.2.tgz
3、编辑harbor配置文件
[root@centos7 app]# cd harbor &&  cp harbor.yml.tmpl harbor.yml
[root@centos7 harbor]# vim harbor.yml
hostname: 192.168.136.31

http:
  port: 80
#https:
#  port: 443
#  certificate: /your/certificate/path
#  private_key: /your/private/key/path

harbor_admin_password: Harbor12345

database:
  password: root123
  max_idle_conns: 100
  max_open_conns: 900
  conn_max_lifetime: 5m
  conn_max_idle_time: 0

data_volume: /data/harbor

trivy:
  ignore_unfixed: false
  skip_update: false
  offline_scan: false
  security_check: vuln
  insecure: false

jobservice:
  max_job_workers: 10
  logger_sweeper_duration: 1 #days

notification:
  webhook_job_max_retry: 3
  webhook_job_http_client_timeout: 3 #seconds

log:
  level: info
  local:
    rotate_count: 50
    rotate_size: 200M
    location: /var/log/harbor

_version: 2.8.0

proxy:
  http_proxy:
  https_proxy:
  no_proxy:
  components:
    - core
    - jobservice
    - trivy

upload_purging:
  enabled: true
  age: 168h
  interval: 24h
  dryrun: false

cache:
  enabled: false
  expire_hours: 24
4、创建存储目录并启动harbor服务
[root@centos7 harbor]#  mkdir /data/harbor -p
[root@centos7 harbor]# ./install.sh
5、此时即可登录浏览器访问Harbor服务
默认账号密码:admin/Harbor12345

使用示例:

# 使用仓库默认的公共项目library推送镜像
1、docker配置文件新增非安全模式配置:insecure-registries
[root@centos7 ~]# vim /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://h03gcjvp.mirror.aliyuncs.com"],
  "insecure-registries": ["192.168.136.31"]

}
[root@centos7 ~]#  systemctl restart docker
2、给镜像打标签
[root@centos7 ~]# docker tag nginx:1.20.2 192.168.136.31/library/nginx:1.20.2 
3、登录刚部署好的harbor,最后显示登录成功即可
[root@centos7 ~]# docker login 192.168.136.31
Username: admin
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
4、上传镜像
[root@centos7 ~]# docker push 192.168.136.31/library/nginx:1.20.2
5、成功后即可登录Harbor看到传输的镜像,内网其他人也可以下载使用

harbor修改配置并使之生效

# 方案一
1、停止服务
[root@centos7 ~]# cd /app/harbor  && docker-compose stop 
2、编辑配置文件,修改如IP,证书等信息
[root@centos7 harbor]# vim harbor.yml 
3、执行prepare脚本,使新配置生效
[root@centos7 harbor]# ./prepare
4、重新启动
[root@centos7 harbor]# docker-compose start

# 方案二
[root@centos7 ~]# cd /app/harbor  && ./install.sh

f.Harbor镜像仓库配置https证书

GO1.15及以上版本程序的X509 不能使用 ,需用SAN证书,如果用新版的docker及harbor,但仍使用x509证书后会报如下错误

docker login harbor.yunrong.com
Username: admin
Password:
Error response from daemon: Get "https://harbor.yunrong.com/v2/": x509: certificate
relies on legacy Common Name field, use SANs or temporarily enable Common Name
matching with GODEBUG=x509ignoreCN=0

配置SAN证书可官网步骤参考

https://goharbor.io/docs/2.8.0/install-config/configure-https/

生成Harbor服务器证书

1#生成ca的私钥
openssl genrsa -out ca.key 4096

2#生成ca的自签名证书
openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj "/C=CN/ST=Zhejiang/L=Ningbo/O=yunrong/OU=yunwei/CN=yunrong.org" \
-key ca.key \
-out ca.crt

#3、生成harbor主机的私钥
openssl genrsa -out harbor.yunrong.org.key 4096

#4、生成harbor主机的证书申请文件
openssl req -sha512 -new \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=harbor.yunrong.org" \
-key harbor.yunrong.org.key \
-out harbor.yunrong.org.csr

#5、创建x509 v3 扩展文件(新版新增加的要求)  
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1=yunrong
DNS.2=yunrong.org
DNS.3=harbor.yunrong.org
EOF

#6、给 harbor主机颁发证书
openssl x509 -req -sha512 -days 3650 -extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in harbor.yunrong.org.csr \
-out harbor.yunrong.org.crt
#7、最终harbor需要使用的证书为如下两个
harbor.yunrong.org.key
harbor.yunrong.org.crt

配置Harbor服务器证书

[root@centos7 ~]# mkdir /app/harbor/certs/
[root@centos7 ~]# cp harbor.yunrong.org.crt harbor.yunrong.org.key /app/harbor/certs/
[root@centos7 ~]# vim /apps/harbor/harbor.yml  主要配置如下https段还有hostname配置扩展证书里存在的域名
hostname: harbor.yunrong.org
http:
  port: 80
https:
  port: 443
  certificate: /app/harbor/certs/harbor.yunrong.org.crt
  private_key: /app/harbor/certs/harbor.yunrong.org.key
......
使配置生效
[root@centos7 ~]# cd /apps/harbor/ && ./prepare
[root@centos7 ~]# docker-compose down -v
[root@centos7 ~]# docker-compose up -d
此时本地配置好域名解析,即可使用域名登录harbor

配置 Docker 客户端使用证书文件

#在harbor服务器上操作
#转换harbor的crt证书文件为cert后缀,docker识别crt文件为CA证书,cert为客户端证书服务器
openssl x509 -inform PEM -in harbor.yunrong.org.crt -out harbor.yunrong.org.cert
#或者
cp -a harbor.wang.org.crt harbor.wang.org.cert   

#在docker客户端服务器上使用上面的证书文件
1、创建存放证书目录
[root@centos7 ~]# mkdir -pv /etc/docker/certs.d/harbor.yunrong.org/ -p
2、将harboar服务器上生成的 harbor.wang.org.cert harbor.wang.org.key ca.crt 上传至docker客户端服务器第一步创建的目录
[root@centos7 ~]# cp harbor.wang.org.cert harbor.wang.org.key ca.crt
/etc/docker/certs.d/harbor.yunrong.org/
3、配置/etc/hosts文件做域名解析
[root@centos7 ~]# echo "192.168.136.31 harbor.yunrong.org"  >> /etc/hosts
4、此时即可通过域名登录并上传镜像等操作
[root@centos7 ~]#  docker login  harbor.yunrong.org
Username: admin
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
推送镜像测试
[root@centos7 ~]# docker tag nginx:1.20.2 harbor.yunrong.org/library/nginx:1.20.2
[root@centos7 ~]# docker push harbor.yunrong.org/library/nginx:1.20.2

g.实现Harbor仓库高可用

Harbor实现高可用的两种方案

Harbor支持基于策略的Docker镜像复制功能,这类似于MySQL的主从同步,其可以实现不同的数据中心、不同的运行环境之间同步镜像,并提供友好的管理界面

部署高可用harbor可参考博客:https://blog.csdn.net/weixin_43266367/article/details/126022696

作者:于浩  创建时间:2025-06-08 21:45
最后编辑:于浩  更新时间:2025-06-10 18:08