########################
(docker 容器进入或访问命令)
docker inspact nginx1
用于查看contain的桥内ip是多少,然后可以在宿主机上查看桥内ip+容器port;然后可以对外eth0网卡映射容器的端口出来。怎么映射出来?
在容器里运行另外一个命令
docker exec nginx1 ls #这个例子看不到任何结果,但是最直接的表述了可以在容器内部执行其他process 进程。
另一个例子
docker exec -t -i nginx1 /bin/sh #这个例子,是用于再打开一个终端从而监控容器是如何运行pid1 的init进程的。一般是这么用的。
因为你要用sh,所以需要一个终端,所以需要t,i是干什么的?交互 i表示交互。
docker attach nginx1 进入到contain的pid 1 的进程中。
##############################
(docker container状态改变命令)
docket pause nginx1 暂停 unpause 继续
OOM 容器使用的内存超过了最大可用量。之后容器stop。如果策略是restart。那么容器将重启。如何制定策略?
docker kill nginx1 强制停止
stop 温柔关闭
#############################################
(docker image 的知识)
bootfs rootfs
底层layer 构建后的layer门(bootfs之上的都叫rootfs)
rootfs 是只读的
在rootfs 层上利用“联合挂载”技术挂载一个可写层。
rootfs 的最底层是base image。base image是它子层的父镜像。
bootfs 在镜像被加载到内存中后,就自动卸载了。从而不占用内存空间。
联合挂载技术:
高级多层统一文件系统 Aufs
之后ubuntu用的是Aufs
centos内核用是devicemapper,来实现联合挂载的
这说的是镜像里的内核
为什么要往容器内部传变量?
因为容器里的配置不好更改,用变量实现更改配置的目的。
docker pull 192.168.0.100:5000/ggc/nginx:1.8
docker pull 私服ip+端口/用户/仓库:tag 端口默认是https的
只做image有两种方法
commit
dockerfile
docker commit -m 'aaaaaaaa' a5151894982e nginx:old 把容器打成镜像
docker tag nginx:old nginx:old.20190713 修改镜像的名字
busybox 是很小的系统镜像
dcoker login 192.168.0.100:5000 -u admin 登录私服
dcoker push nginx 会把nginx 包含各种tag号的版本一并推上去。应该现在先在镜像库中建立nginx的仓库
ggc的阿里云镜像加速地址
https://z12dpm3h.mirror.aliyuncs.com
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://z12dpm3h.mirror.aliyuncs.com","https://99999999.mirror.aliyuncs.com"] 多个加速地址可以这样加
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
aliyun 似库的用法:
1.开通镜像服务
2.修改命名空间为hongmalong
3.创建仓库为nginx 类型为本地上传
4.本地打tag
docker commit -m 'test upload ro aliyun' a5151894982e nginx:old
docker login --username=tianma9641@126.com registry.cn-hangzhou.aliyuncs.com
docker tag nginx:old registry.cn-hangzhou.aliyuncs.com/hongmalong/nginx:old #这个最终tag名称规范来自阿里云。包含了服务器地址,用户空间,仓库名称和版本号
5.上传
docker push registry.cn-hangzhou.aliyuncs.com/hongmalong/nginx:old
docker save -o test.tar.gz nginx:old 保存到本地 -o 是新文件名
docker load -i test.tar.gz -i表示进入
#################################################
(docker 网络模型)
容器A 和容器B 不在同一个宿主机上。
a到b是可以的。b到a是回不来的。因为docker 用物理网卡做了nat,只出不进
k8s 是把a到b的包做了封装,封装上了自己物理网卡的ip,传到对端,对端拆包,转发给容器b。b回包给容器a,物理网卡再次封装自己的物理ip,发给a宿主机。
所以是可逆的。
那么,etcd中保留的路由信息,是给物理网卡看的,还是给容器看的。我感觉是给docker桥接网卡服务看的:容器把包发给docker,docker看flannel。不是自己的,就封装对端物理网卡ip。
到了对端,交给docker服务看,docoker服务查看类型是docker的,然后拆包,发现了自己的虚拟网卡范围内的ip,然后发送给容器。
所以,概括来说:
docker是nat模式通信
k8s 是etcd+docker+flanner+物理网卡 隧道通信
再次说明docker网桥的概念:
把docker网桥看做交换机,交换机有2个端口,一端连接物理网卡,一端连接容器。本身网桥也有一个私网地址。
容器之间通信发到网桥后,会如同在同一个交换机中一样工作,用mac通信。(既然是交换机,那么就可以实现vlan xlan sql等设置)
容器与宿主机沟通,用物理网卡和网桥沟通。由于是网桥,内核位于网桥和物理网卡中间。因此,不用考虑物理ip与网桥ip的段不同的问题。
内核查看路由器表,发现下一跳就在自己的网桥后端。因此就把包发给了自己的网桥。
容器与其他宿主机的容器沟通,需要对端的宿主机用dnat的方式把容器的端口映射出来。同样的,对端容器访问己端容器也需要己端宿主机映射己端容器端口出来。
否则,就只能是同一个宿主机内部的容器相互访问。
##########
容器6中命名空间:
user pid mout net uts ipc
一个容器和另一个容器共享后三个命名空间,也就是他们的网络ip一样,主机名一样,进程间可以通信。
A容器通过127.0.0.1 访问另一个容器的服务,例如tomcat访问redis服务。
如何实现前三个命名空间再一个容器,共享后三个命名空间?
由于宿主机也有上6个命名空间,因此容器也能共享宿主机的后3个命名空间。
docker network ls
中的host ,就是用于让容器a可以共享使用宿主机的后3个命名空间的。
总结:
docker有4中网络模型:
1.容器没有net命名空间,也就没有172.17.段的ip,只用来执行处理任务的工作 #docker run --name t1 --network none --rm -it busybox ifconfig
2.容器有个后3个命名空间,可以通过网桥与外部的nat实现通信 (默认 #用法:docker run --name t1 --network bridge --rm -it busybox ifconfig
3.容器与容器共享后3个命名空间,实现127.0.0.1式的访问 联盟式空间 #docker run --name container1 --rm -i -t busybox; docker run --network container:container1 -i -t --rm --name container2 busybox
4.容器与宿主机共享后3个命名空间,实现容器可以控制宿主机网卡的功能 #docker run --name busybox3 --network host -i -t busybox
第2个模型是一直用的,其他3个模型如何实现?
#################################
(net命名空间的常规操作) 命名空间可以看做是另一套计算机系统,单独拆分出一个部分作为一个对象来看。新建命名空间,那么新建的这个空间独立于原空间,其他空间与原主机共享。
rpm -q iproute #查看是否安装了iproute包,一般都有
ip netns help #查看ip netns的帮助
ip netns add r1 #增加2个命名空间,net空间,其他5个空间与宿主机共享
ip netns add r2 #
ip netns exec r1 ifconfig #查看命名空间的网卡信息,使用ip netns exec +命令
ip netns exec r1 ifconfig -a #
ip link help #
ip link add name veth1.1 type veth peer name veth1.2 #在当前net命名空间中创建2个虚拟网卡,指定他俩是直连的
ip link show #查看直连网卡信息对儿
ifconfig #没激活,所以看不到
ip link set dev veth1.2 netns r1 #把一个网卡给一个命名空间,使用:ip link set dev +devName netns +netNameSpace
ip link show #此时本空间少了一个虚拟网卡
ip netns exec r1 ifconfig -a #
ip netns exec r1 ip link set dev veth1.2 name eth0 #重命名命名空间中的网卡名。ip netns exec r1 +命令:ip link set dev 原名称 name 新名称
ip netns exec r1 ifconfig -a #
ifconfig veth1.1 10.1.0.1/24 up #给当前空间内的网卡添加临时ip
ip netns exec r1 ifconfig eth0 10.1.0.2/24 up #给命名空间内的网卡添加临时ip
ping 10.1.0.2 #在当前命名空间中ping对端
ip link set dev veth1.1 netns r2 #将第一个虚拟网卡挪到命名空间2中去
ifconfig -a #
ip netns exec r2 ifconfig -a #
ip netns exec r2 ifconfig veth1.1 10.1.0.3/24 up #在第2个命名空间中给网卡设置ip
ip netns exec r2 ping 10.1.0.2 #在第2个空间中ping对端
这里建立了2个命名空间,如果在把这2个命名空间给容器,就实现了容器的直连。
#############################仅仅一个命令而已,没什么用。
docker run --name t2 --network bridge -it -h master --dns 8.8.8.8 --add-host "www.baidu.com:1.1.1.1" --rm busybox ifconfig;cat /etc/resolv.conf;cat /etc/hosts
--network bridge host none 3中方式可选,指定容器的网络类型
-h 指定主机名
--dns 指定容器内部dns
--add-host 添加host解析,无效!!!!
--rm 运行即销毁
busybox 很小的操作系统
############################################## docker 网络散知识开始了
容器对外暴露端口 4中方法: #
docker run --name nginx1 -d -p 80 nginx #不指定nat的外部端口是大于32768的任意端口
netstat -tupln|grep 80 #
docker run --name nginx2 -d -p 8000:80 nginx #前面的8000是nat的外部端口
netstat -tupln|grep 80 #
docker run --name nginx3 -d -p 192.168.0.80:8001:80 nginx #指定nat的网卡是哪个,或许有多个网卡
netstat -tupln|grep 80 #
docker run --name nginx4 -d -p 192.168.0.80::80 nginx #指定网卡,而不指定端口,端口号随机。
netstat -tupln|grep 80 #
iptables -t nat -vnL
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32770 to:172.17.0.2:80
# 这是nat指向语句
docker port nginx1 #这是查看容器port 映射情况的命令
docker run -d --name nginx2 -P nginx #-P 大p表示映射全部容器开放的端口到nat外部,nat外部的端口号随机
########################################
docker run -d nginx1
docker run --rm nginx2
-d 与 --rm 冲突,只能一次用一个。
#####################################
修改docker默认网桥的网段
vi /etc/docker/daemon.json
{
"bip":"10.0.0.1/24"
}
#
docker network create --help #
docker network create --subnet '172.19.0.0/16' --gateway '172.19.0.1' mybr01 #创建新的虚拟网桥,分配新的ip段
docker network ls #
docker run --name brtest --rm --network mybr01 busybox ifconfig #使用新的网桥建容器
ip link set dev br-42d90cabfd80 name mydr01 #在当前命名空间内可以给新网桥重命名
docker run --network mybr01 -i -t --rm --name t1 busybox
docker run -t -i --rm --name t2 --network bridge busybox #这样就隔离开了同一个主机上不同容器之间的访问
##########################################
(docker 存储卷)
docker run --name t1 -i -t -v /docker/vm/t1:/data busybox #/docker/vm/t1 宿主机目录
docker run --name t2 -i -t --volumes-from t1 busybox #--volumes-from t1 使用t1的存储卷
docker inspect -f {{.HostConfig.Binds}} t1 #-f {{.HostConfig.Binds}} go模板格式
##########################################
(docker file)
.dockeringore 文件用于写忽略文件复制列表(可以用通配符)
shell用法:
echo ${NAME:-TOM} # 如果没有name这个赋值就用tom
NAME='JACK' # 如果有赋值就用jack
echo ${NAME:-TOM} #
echo ${NAME:+JIMI} # 如果有赋值就用jimi
FROM 192.168.0.100:5000:mph/nginx:1.4 #服务器信息是可以省的,如果不写就是dockehup
FROM 192.168.0.100:5000:@哈希码 #哈希码用于取唯一的镜像,而不会被其他人顶替镜像 推荐
MAINTANIER 作者 ggc ggc@abc.com
COPY a.sh /a.sh #复制文件
COPY a.sh b.sh c.sh / #复制多个文件
COPY *.sh / #复制多个文件+支持通配符
WORKDIR /
COPY a.sh a.sh #workdir+copy 从而省了指定目标目录
workdir #可以指定多次,每次指定只影响从它向后的指令
COPY a b /bdir/ #复制多个文件目标必须是目录,且必须以/结束。!!!!!!!
可以多次copy
docker build -t mph/nginx:1.5 .或/a/或http://***** 只要当前目录或指定目录,或url中有dockerfile就行。
跟copy类似的还有add
ADD a /a #
ADD http://ssss.sh a.sh #文件源可以是url
ADD a.tar.gz /a/ #结果是/a/a 会自动解包,类似tar -xz
ADD http://ssss.tar.gz /a/ #url中的tar包不会被解压
ADD a b /a/ #原是多个文件,目标要是带/的目录
VOLUME /data/ #真要是这样指定了,那么容器启动后会在宿主机上创建目录,把经常修改的文件放入/data目录下,存在宿主机上。
虽然存了,但是不好找,因为在宿主机上的路径要用docker inspact查看对应关系才行。
EXPOSE 80 #暴露端口出去
ENV name gao guagnchao #第一个是key 后面的都是值
ENV first_name=gao seconde_name=guangchao #用等号=可以定义多个环境变量
ENV PATH=\$JAVA:\$PATH #可以用反斜线转义
ENV filename='a b' #可以用引号
ENV loneworld=aaaaaaaaaaaa \ #可以用与续行
bbbbbbbbbbbbb #
build时用到的这些变量,在run时也可以printevn拿到
docker run -e name="ggk" busybox printevn #可以在运行容器时指定环境变量
CMD /bin/bash #容器运行时,默认执行的命令
RUN mkdir /a #构建镜像时,执行命令
RUN ['/bin/bash','-c','yum','intall','httpd','-y'] #RUN ['/bin/bash','-c',***] 这样可以在shell环境下使用命令。否则就是在内核环境下使用命令,会有些不便
CMD ['nginx','-d'] #在内核环境下启动nginx,且一直不退出
exec ping 127.0.0.1 不会退出
exec 会使当前进程id变为1,shell退出,执行本进程,如果本进程结束,tty结束。
RUN yum install httpd -y #在shell下执行 #进程号不为1 # #
RUN ['rm','-f','/a.*'] #不在shell下执行 # # #不能使用通配符
RUN ['/bin/bash','-c','rm','-f','/a.*'] #在shell下执行 # # #可以使用通配符
# # # #
CMD /bin/httpd -f -h ${WEB_DOC_ROOT} #在shell下执行 #进程号为1 exec#可以接收stop的信号,会随系统停止而停止 #可以使用通配符 #exec +命令。自动替换成了这样的了
#自动改为"Cmd": ["/bin/sh","-c","/bin/httpd -f -h ${WEB_DOC_ROOT}"],
CMD ['/bin/httpd','-f','-h ${WEB_DOC_ROOT}']#不在shell下执行 #进程号为1 #可以接收stop的信号,会随系统停止而停止 #不能使用通配符和$符
"Cmd": ["/bin/sh","-c","/bin/httpd -f -h ${WEB_DOC_ROOT}"],
docker exec -it ca96fe461c8b /bin/sh #进入容器内部,以其他tty进入
RUN yum install httpd -y #在shell下执行
RUN ['/bin/bash','-c','rm','-f','/a.*'] #强制夺取shell的pid
CMD /bin/httpd -f -h ${WEB_DOC_ROOT} #自动强制在shell下执行
CMD ['/data/web/html'] #作为参数补充
ENTRYPOINT ["/bin/sh","-c","/bin/httpd","-f","-h"] #会把cmd当做参数加进来。 "/bin/sh","-c" 最好用着
虽然理论知道了,但是实操是另外一回事。
USER root
HEALTHCHECK 健康监测
HEALTHCHECK --interval=5m --timeout=3s --start-period=10s --retries=3
CMD curl -f http://localhost/ ||exit 1
监控频率5m,超时3s,晚于容器启动时间10s开始检测,尝试3次
状态为1 ,就退出容器,保证nginx死,容器也死。
######################
ci #持续集成 代码提交自动构建
cd #持续交付 构建完成自动测试
cd #持续部署 测试完自动发布
蓝绿部署,灰度部署,金丝雀
#############################
api接收信息,
schedule收集服务器负载,权衡该把这个容器放在哪个node节点上
proxy 在node节点上接收schedule发送过来的信息
kubelet 指挥docker服务启动容器,按需启动
kubelet监控本机容器运行情况,跟dns服务交互,重启容器。node节点关机,自由pod无法在k8s集群中自动恢复。有pod控制器的pod,可以在k8s集群控制下在别的node上恢复。
control 监控node节点运行情况
control-manager监控control运行情况
master三个节点相互监控,随时夺取master身份
对k8s来看pod是最小单元
一个pod里面有多个容器,共享6个命名空间,模拟一台虚拟机。一般一个pod一个容器
在docker来看,最小单元是容器
多个pod,一个标签,多个标签,用标签选择器选择。
监控多个pod运行状态的服务,和监控pod内部服务运行状态的服务,是replictaionControler:pod个数,pod状态,服务状态,pod迁移,podreolad 它都负责
pod控制器的种类:
replictaionControler 最早的pod控制器
replicaset
deployment 只能控制无状态pod 常用 nginx 它支持伸缩控制器 hpa 水平伸缩自动控制器,自动加pod数量
statefulset 控制有状态pod tomcat mysql redis mq
deamonset 一个node上运行一个pod,其他pod在其他node上运行,这些pod是一组
job cronjob 定时任务pod管理器,保证任务执行完成再销毁
#######################################控制器
client pod 通过service(vip)来实现访问提供服务的 pod(realserver)
dns pod 负责解析service pod的地址ip,提供服务的pod把标签+ip+port注册进serice
dns pod属于k8s的附件
service(vip)提供ip+port代理 即dnat目标代理
service(vip)实际用的iptables规则显示的dnat
为了承载更多访问量,将iptables规则改为了ipvs规则。实现了内核转发,效率更高了。
AddOns 附件组件包括:
dns pod
基于k8s的可自动按需扩展精神,一切创建出来的,新加上的都有集群service
最最前端的nginx也是pod,也有service,这个nginx负责加载配置文件
这个nginx前面还需要代理,这个代理是用于读取nginx的serice的,并对外暴露ip,
从这里开始就不在k8s集群了。
多个代理前面需要有lsb服务或者h5或者lvs+keepalived
pod控制器可以创建pod,pod发布服务的serice需要手工创建
service有2中,一种是给集群内部使用的,一种是给集群外部使用的,那就不需要在nginx的service前面加带了了直接上有了外部ip了,让slb直连这个service不就行了吗?
控制器让pod更好管
service让pod更好访问
dns让servie更好给知道
标签让service更好知道pod
###############################pod网络和service网络
pod网络 service网络 网段不同
节点物理网络
这是k8s需要的三种网络
pod内容器间的通信
pod与pod之间的通信
pod与service的通信,他俩不在同一个网段,pod指向docker0桥当做网关,网关查iptables规则,显示访问。
这是k8s的3中通信
overlay 网络,pod与其他node的pod通过隧道封装技术通信
pod关机,service通过标签知道了,a标签死了,被kube_proxy知道了,在通知api,再通知其他node的kube_proxy。
pod创建,service通过标签知道了。................
service 的动态更新是由kube_proxy处理的。kube_proxy因为知道了service下的pod改变了,所以修改了iptables或ipvs。
service的变更由kube_proxy处理。
service的变更由kube_proxy处理。
service的变更由kube_proxy处理。
kube_proxy 需要修改全部节点上的iptables规则.
###############################数据中心
masters的数据存在共享存储上 ---》 etcd
etcd节点与节点之间的通信用https
etcd与kube_apiserver联系用http 或 https
kube_apiserver与kube_apiserver之间 通信用https
kube_apiserver 与kube_proxy 通信用https
kube_apiserver 与kubelet 通信用https
这最好五个ca用于签发证书
#################################
(k8s的网络) #
flannel 网络配置 #简单
calico 网络配置,网络策略 #复杂
canel 网络配置,网络策略 #适中
#########################
领悟:
既然容器可以用host来共享使用宿主机的net命名空间,那么用容器启动nginx服务,使用宿主机的net命名空间即ip,就跟在宿主机上运行nginx一样。
换言之,kube_apiserver schedule kube_control_manager,kube_proxy,etcd ,flannel都一个运行在容器里。
为什么kubelet不能运行在容器里?
###################################################################################################
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
vi /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes Repo
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
enabled=1
yum repolist |grep -E 'docker|kubernetes'
ssh-keygen -t rsa
ssh-copy-id -i root@192.168.0.102
yum install kubelet-1.11.1 -y
python-requests-2.6.0-1.el7_1.noarch has missing requires of python-urllib3 >= ('0', '1.10.2', '1')
pip uninstall urllib3
yum reinstall python-requests -y
scp /etc/yum.repos.d/CentOS-Base.repo root@192.168.0.102:/etc/yum.repos.d/CentOS-Base.repo
yum install docker-ce kubeadm-1.11.1 kubectl-1.11.1 -y
Public key for 14bfe6e75a9efc8eca3f638eb22c7e2ce759c67f95b43b16fae4ebabde1549f3-cri-tools-1.13.0-0.x86_64.rpm is not installed
sed -i 's/gpgcheck=1/gpgcheck=0/g' /etc/yum.repos.d/kubernets.repo
yum install docker-ce kubeadm-1.11.1 kubectl-1.11.1 -y
#关闭key检查就好了
systemctl start docker
systemctl enable docker
cat /proc/sys/net/bridge/bridge-nf-call-iptables
1
此后kubelet会操作iptables
rpm -ql kubelet
cat /etc/sysconfig/kubelet
不使用swap
kubeadm init --kubernetes-version=v1.11.1 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12
yum install https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/docker-ce-selinux-17.03.0.ce-1.el7.centos.noarch.rpm -y
echo deltarpm=0 >> /etc/yum.conf && yum -y update polkit && sed -i ':a;$!{N;ba};s/\ndeltarpm=0//g' /etc/yum.conf && yum -y update
yum remove docker-ce
yum list docker
yum erase docker.x86_64
yum list container-selinux-2.99-1.el7_6.noarch
yum erase container-selinux.noarch
yum install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch.rpm -y
yum install https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/docker-ce-17.03.0.ce-1.el7.centos.x86_64.rpm -y