一、docker基础

1、docker安装

参考文章:

2、docker命令

参考文章:

3、版本信息

要求:系统内核版本3.10及以上
分为:CE社区版免费(17.03,17.06,17.09,17.12,18.03,18.06,18.09,19.03,20.10)和EE企业收费版

4、存储引擎

https://docs.docker.com/storage/storagedriver/select-storage-driver/ 推荐使用:overlay2
故障案例:

5、docker内部通信流程:
1. dockerd 通过 grpc 和 containerd 模块通信,dockerd 和 containerd 通信文件:/run/containerd/containerd.sock。
2. containerd 在 dockerd 启动时被启动,然后 containerd 启动 grpc 请求监听,containerd 处理 grpc 请求,根据请求做相应动作。
/usr/bin/dockerd -H fd://--containerd=/run/containerd/containerd.sock
3. 若是创建容器,containerd 拉起一个 container-shim , 并进行相应的创建操作。
4. container-shim 被拉起后,start/exec/create 拉起 runc 进程,通过 exit、control文件和containerd 通信,通过父子进程关系和 SIGCHLD(信号)监控容器中进程状态。
5. 在整个容器生命周期中,containerd 通过 epoll 监控容器文件,监控容器事件

gRPC:是Google开发的一款高性能、开源和通用的RPC框架,支持众多语言客户端。https://www.grpc.io/

二、基础的容器运行环境

1、Namespace:实现容器运行空间的相互隔离

属于内核层
所有容器共用宿主机内核

(1)MNT Namespace:文件系统、磁盘挂载点的隔离

#宿主机是Ubuntu,容器可以是centos。容器里起的服务如nginx的运行环境为centos,而无法访问主机资源。
# uname -r
#宿主机使用chroot技术将容器锁定到指定的运行目录里
#/var/lib/containerd/io.containerd.runtime.v2.task/moby/容器 ID

实验:

#启动三个容器用于以下验证过程:
# docker run -d --name nginx-1 -p 80:80 nginx
# docker run -d --name nginx-2 -p 81:80 nginx
# docker run -d --name nginx-3 -p 82:80 nginx

#Debian 系统安装基础命令:
# apt update
# apt install procps (top 命令)
# apt install iputils-ping (ping 命令)
# apt install net-tools (网络工具)

#验证容器的根文件系统:
# cat /etc/redhat-release
# docker exec -it 5a7c6090b8adae677c8c sh
#1s / #容器的根文件系统,每个容器都有一个独立且完整的根文件系统
bin boot dev etc home index.html lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

(2)IPC Namespace:进程间通信的隔离
允许一个容器内的进程间通信,不能跨容器访问

(3)UTS Namespace:主机名、域名的隔离
用于系统标识,包含主机名和域名,各容器唯一,互相独立

# hostname
# cat /etc/issue

(4)PID Namespace:进程的隔离
宿主机父进程init/systemd(pid=1)
容器内进程互相独立(可存在不同容器间pid相同,等)

#宿主机pid与容器pid关系:
# ps -ef |grep docker #1806之后的版本
systemd(1)-->dockerd(被client直接访问)-->docker-proxy(实现容器通信)
systemd(1)-->containerd(被dockerd进程调用以实现与runc的交互)-->containerd-shim(真正运行容器的载体)-->nginx(容器内服务)(master)-->nginx(worker)

# ps -ef |grep nginx
# top -n 1
worker-->master(pid=1)

(5)Net Namespace:网卡、监听端口、TCP/IP 协议栈等的隔离
docker0 虚拟网桥 数据链路层 mac地址划分网络

# ifconfig
# brctl show #查看宿主机桥接设备
# iptables -t nat -vnL #宿主机iptables规则
# iptables -vnL

(6)User Namespace:用户名、组名、UID、GID的隔离
仅在当前容器有效,互相隔离、互不影响

# id
2、Cgroups

属于内核层
宿主机对容器进行资源分配限制,如CPU、内存、磁盘、网络带宽、进程等

# cat /boot/config-4.15.0-20-generic | grep CGROUP  #内核层默认开启,ubuntu支持功能更多
# cat /boot/config-4.15.0-20-generic | grep MEM |grep CG  #cgroups中内存模块
# ll /sys/fs/cgroup/  #cgroups具体实现
	blkio          			#块设备 IO 限制
	cpu -> cpu,cpuacct    	#使用调度程序为 cgroup 任务提供 cpu 的访问
	cpuacct -> cpu,cpuacct  #产生 cgroup 任务的 cpu 资源报告
	cpu,cpuacct     		
	cpuset      		  	#如果是多核心的 cpu,这个子系统会为 cgroup 任务分配单独的 cpu 和内存
	devices       			#允许或拒绝 cgroup 任务对设备的访问
	freezer       			#暂停和恢复 cgroup 任务
	hugetlb       			#
	memory      			#设置每个 cgroup 的内存限制以及产生内存资源报告
	net_cls -> net_cls,net_prio   	#标记每个网络包以供 cgroup 方便使用
	net_cls,net_prio  				
	net_prio -> net_cls,net_prio    #
	perf_event       		#增加了对每 group 的监测跟踪的能力,可以监测属于某个特定的 group 的所有线程以及运行在特定 CPU 上的线程
	pids       				#
	systemd       			#

三、容器管理工具

早期:lxc
目前:docker
docker的镜像是分层的,底层是库文件只读层,开启为容器后生成可写层,数据只停留在容器中。

1、容器的核心技术:

容器管理工具
runtime 真正运行容器的地方
#cat /run/docker/runtime-runc/moby/容器1D/state.json #规范
Runc的管理工具是docker engine(docker),docker engine包含后台deamon和cli两部分

容器定义工具
Docker image:是docker容器的模板,runtime 依据docker image创建容器。
Dockerfile:包含N个命令的文本文件,通过dockerfile创建出docker image。

容器镜像仓库
Image registry:docker 官方提供的私有仓库部署工具
Docker hub:docker 官方的公共仓库
Harbor:vmware 提供的自带 web 界面自带认证功能的镜像仓库

容器编排工具
Docker swarm:docker 开发的容器编排引擎。
Kubernetes:google 开发的容器编排引擎,内部项目为 Borg,且其同时支持docker 和 CoreOS。

2、容器的依赖技术:

容器网络
docker network:docker 自带的网络 ,仅支持管理单机上的容器网络,
calico/flannel 等:第三方开源网络,多主机运行时需要使用

服务发现
kubernetes 自带服务发现功能,需要结合 kube-dns 服务解析内部域名。

容器监控:
docker ps/top/stats:命令查看容器运行状态
heapster/ Prometheus等:第三方监控工具监控容器的运行状态

数据管理:
容器的动态迁移使用逻辑卷/存储挂载等方式

日志收集:
docker logs:命令查看日志
ELK 等:专门的日志收集分析和展示工具进行处理

四、Dockerfile

常用指令:
# 为注释
FROM #整个dockfile文件中,除了注释外的第一行必须是FROM,用于指定父镜像(本地仓库没有会从远程仓库下载)
ADD #宿主机本地资源添加至镜像中,自动解压tar.gz格式
COPY #宿主机本地资源添加至镜像中
LABEL #设置镜像的属性标签(镜像的作者信息)
ENV #设置容器环境变量,常用于向容器内传递用户密码等
USER #指定该容器运行时的用户名和 UID
RUN  #执行shell命令,以非交互式的方式
CMD #镜像启动为一个容器时的默认命令或脚本 #每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。
ENTRYPOINT #每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。,docker run命令指定的容器运行命令不能覆盖Dockerfile文件中ENTRYPOINT指令指定的命令,反而被当做参数传递给ENTRYPOINT指令指定的命令。
EXPOSE #声明映射的端口
STOPSIGNAL 
VOLUME #设置容器挂载主机目录
WORKDIR #定义工作目录
MAINTAINER  #镜像维护者的信息
将自制的镜像上传至 docker 仓库:
#将自制的镜像上传至 docker 仓库;https://hub.docker.com/
[root@linux-docker ~]# docker login https://hub.docker.com/  #登录
[root@linux-docker ~]# docker images #查看镜像 ID
[root@linux-docker ~]# docker tag 678e2f074b0d docker.io/zhangshijie/centos-nginx #为镜像做标记
[root@linux-docker ~]# docker login #默认即登录到 docker 官方网站
[root@linux-docker ~]# docker push docker.io/zhangshijie/centos-nginx #上传至仓库
#到 docker 官网验证
#在其他 docker 服务器下载该镜像并启动为容器
案例:

参考本地压缩包:dockerfile-n56.tar.gz

docker部署speedtest报错403_tomcat


docker部署speedtest报错403_nginx_02

五、docker数据持久化

docker数据管理/如何实现容器中数据的持久化

原理:

写时复制COM (copy on write)机制:保存在可写层同时保存在宿主机volume,实现数据持久化

#容器数据在宿主机上的存放位置
# ll /var/lib/docker/overlay2/978a71a1bf6b93fcf05bb4921d7cc11ff697770812cf6f85fcb5688099ea88e2/diff/ #容器的文件系统在宿主机的位置
两种常见的实现方式:
1、数据卷(data value)

宿主机上的目录或文件,被mount到容器中使用(支持多容器共同使用)。数据卷的数据可永久保存在宿主机,删除容器不受影响。

实战案例:

#1:创建 APP 目录并生成 web 页面: 
[root@docker-server1 ~]# mkdir testapp 
[root@docker-server1 ~]# echo "Test App Page" > testapp/index.html 
[root@docker-server1 ~]# cat testapp/index.html 

#2:启动容器并验证数据: #注意使用-v 参数,将宿主机目录映射到容器内部
[root@docker-server1 ~]# docker run -d --name web1 -v /root/testapp/:/apps/tomcat/webapps/testapp -p 8811:8080 tomcat-web:app1
[root@docker-server1 ~]# docker run -d --name web2 -v /root/testapp/:/apps/tomcat/webapps/testapp:ro -p 8812:8080 tomcat-web:app2 #ro只读,默认可读写

#3:进入到容器内测试写入数据: 
[root@docker-server1 ~]# docker ps
rootddocker-server1:# docker exec-it 463bf7548b72 bash
[root@463bf7548b72 /]# cat /apps/tomcat/webapps/testapp/index.html
testapp page.
[root@463bf7548b72 /]# exit
#宿主机验证: 
[root@docker-server1 ~]# cat testapp/index.html
#web 界面访问:
192.168.100.101:8811/testapp
test app page
192.168.100.101:8812/testapp
test app page 

#4:在宿主机修改数据:#宿主机更改信息后在所有容器立即生效 
[root@docker-server1 ~]# echo "1111" >> testapp/index.html 
[root@docker-server1 ~]# cat testapp/index.html 
Test App Page
1111
#web 端访问验证数据: 
192.168.100.101:8811/testapp
test app page docker 1111
192.168.100.101:8812/testapp
test app page docker 1111

#5:删除容器: 
#创建容器的时候指定参数-v,可以删除/var/lib/docker/containers/的容器数据目录,但是不能删除数据卷的内容
#验证宿主机的数据:
[root@docker-server1 ~]# cat testapp/index.html

文件挂载实战案例:

#1:创建容器并挂载文件: 
[root@docker-server1 ~]# ll testapp/catalina.sh 
-rwxr-xr-x 1 root root 23705 Jul 3 14:06 testapp/catalina.sh
#自定义 JAVA 选项参数:
JAVA_OPTS="-server -Xms4g -Xmx4g -Xss512k -Xmn1g 
-XX:CMSInitiatingOccupancyFraction=65 -XX:+UseFastAccessorMethods -XX:+AggressiveOpts 
-XX:+UseBiasedLocking -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=10 -XX:NewSize=2048M
-XX:MaxNewSize=2048M -XX:NewRatio=2 -XX:PermSize=128m -XX:MaxPermSize=512m -XX:CMSFullGCsBeforeCompaction=5 
-XX:+ExplicitGCInvokesConcurrent -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled 
-XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods"
#创建容器
[root@docker-server1 ~]# docker run -d --name web1 -v /root/bin/catalina.sh:/apps/tomcat/bin/catalina.sh:ro -p 8811:8080 tomcat-web:app1

#验证参数生效: 
[root@docker-server1 ~]# docker ps
[root@docker-server1 ~]# ps -ef |grep tomcat

#进入容器测试文件读写
root@docker-server1:~# docker exec-it 2e90299a3916 bash
[root@2e90299a3916 /]# echo "test">>/apps/tomcat/bin/catalina.sh 
bash:/apps/tomcat/bin/catalina.sh:Read-only file system

#2:如何一次挂载多个目录: 
[root@docker-server1 ~]# docker run -d --name web1 -v /root/bin/catalina.sh:/apps/tomcat/bin/catalina.sh:ro -v /root/testapp:/apps/tomcat/webapps/testapp -p 8811:8080 tomcat-web:app1
[root@docker-server1 ~]# docker run -d --name web2 -v /root/bin/catalina.sh:/apps/tomcat/bin/catalina.sh:ro -v /root/testapp:/apps/tomcat/webapps/testapp -p 8812:8080 tomcat-web:app2

数据卷使用场景:
(1)日志输出
(2)静态web页面
(3)应用配置文件
(4)多容器间目录或文件共享

2、数据容器(data value container)

将数据保存在一个容器上,为其他容器提供存储服务。
实战案例:

#1:先启动一个卷容器 Server,并挂载宿主机的数据目录:
[root@docker-server1 ~]# docker run -d --name volume-docker -v /root/bin/catalina.sh:/apps/tomcat/bin/catalina.sh:ro -v /root/testapp:/apps/tomcat/webapps/testapp tomcat-web:app2
#2:启动两个端容器 Client: 
[root@docker-server1 ~]# docker run -d --name web1 -p 8801:8080 --volumes-from volume-docker tomcat-web:app1
[root@docker-server1 ~]# docker run -d --name web2 -p 8802:8080 --volumes-from volume-docker tomcat-web:app2
#3:分别进入容器测试读写: 读写权限依赖于源数据卷 Server 容器
#4:关闭卷容器 Server,测试能否启动新容器: 
[root@docker-server1 ~]# docker stop volume-docker
[root@docker-server1 ~]# docker run -d --name web3 -p 8803:8080 --volumes-from volume-docker tomcat-web:app2 #可以创建新容器
#5:删除卷容器 Server,测试能否启动新容器: 
[root@docker-server1 ~]# docker rm -fv volume-docker
[root@docker-server1 ~]# docker run -d --name web4 -p 8804:8080 --volumes-from volume-docker tomcat-web:app2 #无法创建新容器
docker: Error response from daemon: No such container: volume-docker.See 'docker run --help'.

#6:测试之前的容器是否正常: 已经运行的容器不受任何影响
#7:重新创建容器卷 Server: 
[root@docker-server1 ~]# docker run -d --name volume-docker -v /root/bin/catalina.sh:/apps/tomcat/bin/catalina.sh:ro -v /root/testapp:/apps/tomcat/webapps/testapp tomcat-web:app
[root@docker-server1 ~]# docker run -d --name web4 -p 8804:8080 --volumes-from volume-docker tomcat-web:app2

六、harbor镜像

1、特性:

基于角色的访问控制:用户权限
镜像复制
图像化用户界面
AD/LDAP 支:活动记录,鉴权认证管理
审计管理:所有针对镜像仓库的操作都可以被记录追溯
国际化:支持多国语言的版本
RESTful API:约定接口规范,与其它管理软件集成变得更容易。
部署简单:支持在线和离线安装,也可以安装到 vSphere 平台(OVA 方式)虚拟设备。

2、组件:

nginx:harbor的一个反向代理组件,代理registry、ui、token等服务。这个代理会转发harbor web和docker client的各种请求到后端服务上。
harbor-adminserver:harbor系统管理接口,可以修改系统配置以及获取系统信息。
harbor-db:存储项目的元数据、用户、规则、复制策略等信息。
harbor-jobservice:harbor里面主要是为了镜像仓库之前同步使用的。
harbor-log:收集其他harbor的日志信息。
harbor-ui:一个用户界面模块,用来管理registry。
registry:存储docker images的服务,并且提供pull/push服务。
redis:存储缓存信息
webhook:当registry中的image状态发生变化的时候去记录更新日志、复制等操作。
token service:在docker client进行pull/push的时候负责token的发放。

3、安装:

下载地址:https://github.com/vmware/harbor/releases 安装文档:https://github.com/vmware/harbor/blob/master/docs/installation_guide.md

#(1)安装并启动docker
#(2)安装habor
[root@docker-server1 ~]# cd /usr/local/src/
[root@docker-server1 src]# tar xf harbor-offline-installer-v2.3.2.tgz
[root@docker-server1 src]# ln -sv /usr/local/src/harbor /usr/local/
‘/usr/local/harbor’ -> ‘/usr/local/src/harbor’
[root@docker-server1 src]# cd /usr/local/harbor/
[root@docker-server1 harbor]# grep "^[a-Z]" harbor.cfg 
hostname = 192.168.10.205 
ui_url_protocol = http
db_password = root123
max_job_workers = 3 
customize_crt = on
ssl_cert = /data/cert/server.crt
ssl_cert_key = /data/cert/server.key
secretkey_path = /data
admiral_url = NA
clair_db_password = password
email_identity = harbor
email_server = smtp.163.com
email_server_port = 25
email_username = rooroot@163.com
email_password = zhang@123
email_from = admin <rooroot@163.com>
email_ssl = false
harbor_admin_password = zhang@123
auth_mode = db_auth
ldap_url = ldaps://ldap.mydomain.com
ldap_basedn = ou=people,dc=mydomain,dc=com
ldap_uid = uid 
ldap_scope = 3 
ldap_timeout = 5
self_registration = on
token_expiration = 30
project_creation_restriction = everyone
verify_remote_cert = on
# yum install python-pip -y
# pip install --upgrade pip  #升级 pip 为最新版本
# pip install docker-compose  #安装 docker-compose命令
# ./install.sh  #官方构建 harbor 和启动方式,推荐此方法,会下载官方的 docker 镜像
#验证:
# docker images  #查看本地镜像
# ss -ntl  #查看本地端口
#web访问habor管理界面

#(3)首次部署 harbor 更新: 
# cd /usr/local/harbor  #在 harbor当前目录执行
# ./prepare #更新配置
#执行完毕后会在当前目录生成一个 docker-compose.yml 文件,用于配置数据目录等配置信息

#(4)后期修改配置: 
#如果 harbor 运行一段时间之后需要更改配置,则步骤如下:
# cd /usr/local/harbor
# docker-compose stop
# vim harbor.cfg
# ./prepare
# docker-compose start
4、给 docker 配置 harbor 仓库并测试使用:
#(1)给 docker 配置 harbor 仓库
#注意:如果我们配置的是 https 的话,本地 docker 就不需要有任何操作就可以访问 harbor 了
[root@docker-server1 ~]# vim /etc/sysconfig/docker
4 OPTIONS='--selinux-enabled --log-driver=journald --insecure-registry 192.168.10.205' #其中 192.168.10.205 是我们部署 Harbor 的地址,即 hostname 配置项值。配置完后需要重启 docker 服务。
[root@docker-server1 ~]# systemctl restart docker
[root@docker-server1 harbor]# docker login 192.168.10.205  #验证能否登录 harbor

#(2)测试上传镜像至 habor 
[root@docker-server1 harbor]# docker load < /opt/nginx-1.10.3_docker.tar.gz #导入镜像 
[root@docker-server1 harbor]# docker images 
[root@docker-server1 harbor]# docker tag 192.168.10.205:5000/jack/nginx-1.10.3:v1 192.168.10.205/nginx/nginx_1.10.3:v1 
[root@docker-server1 harbor]# docker images
#在 harbor 管理界面创建项目
[root@docker-server1 harbor]# docker push 192.168.10.205/nginx/nginx_1.10.3:v1  #将镜像 push 到 harbor
#harbor 界面验证镜像上传成功
#验证镜像信息

#(3)测试从 habor 下载镜像
[root@docker-server2 ~]# docker pull 192.168.10.205/nginx/nginx_1.10.3:v1
[root@docker-server2 ~]# docker run -d -p 80:80 -p 443:443 192.168.10.205/nginx/nginx_1.10.3:v1 nginx
#验证端口
#验证web访问
5、实现 harbor 高可用:
#(1)实现单向复制
#新部署一台从 harbor 服务器
#验证web登录从 habor
#在从 habor 上创建一个nginx项目,与主 habor 项目名称保持一致
#在主 harbor 服务器配置同步测试:点击复制规则-完善信息-测试-确定
#在从 habor 验证镜像同步情况
#测试从 harbor 镜像下载和容器启动

#(2)实现 harbor 双向同步:
#往从 harbor 推送镜像
#在从 harbor 创建同步规则:规则方式与主 harbor 相同,写对方的 IP+用户名密码-测试连接-确定
#在主 habor 验证镜像同步情况
#测试主 harbor 镜像下载和容器启动
6、harbor https 配置:
# openssl genrsa -out /usr/local/src/harbor/certs/harbor-ca.key 2048
# openssl req -x509 -new -nodes -key /usr/local/src/harbor/certs/harbor-ca.key -subj "/CN=harbor.magedu.net" -days 7120 -out /usr/local/src/harbor/certs/harbor-ca.crt
# vim harbor.cfg
 hostname = harbor.magedu.net
 ui_url_protocol = https
 ssl_cert = /usr/local/src/harbor/certs/harbor-ca.crt
 ssl_cert_key = /usr/local/src/harbor/certs/harbor-ca.key
 harbor_admin_password = 123456
# ./install.sh
# yum install docker-ce-18.06.3.ce-3.el7.x86_64.rpm
# yum install docker-compose
# mkdir /etc/docker/certs.d/harbor.magedu.net -p
# cp certs/harbor-ca.crt /etc/docker/certs.d/harbor.magedu.net/
# docker login harbor.magedu.net
#登录测试