Docker 翻转课堂第 4 次文字答疑

1. k8s集群安装成功,skydns插件也安装成功,然后通过NodePort暴露的⽅式应⽤可以访问,通过clusterip:port端⼝访问失败,不知道是哪⾥配置有问题,请⽼师帮忙分析⼀下。

[root@ip-10-28-64-205 dede-k8s]# kubectl describe svc dede-app-test
 Name: dede-app-test
 Namespace: default
 Labels: run=dede-app-test
 Selector: run=dede-app-test
 Type: NodePort
 IP: 10.100.75.35
 Port: <unset> 8083/TCP
 NodePort: <unset> 30063/TCP
 Endpoints: 172.17.40.4:8081,172.17.80.5:8081
 Session Affinity: None
 No events.
[root@ip-10-28-64-205 dede-k8s]# curl 10.100.75.35:8083
 curl: (7) Failed connect to 10.100.75.35:8083; 连接超时
[root@ip-10-28-64-205 dede-k8s]# curl -s 10.27.248.183:30063/rest/hello
 "Hello World"
[root@ip-10-28-64-205 dede-k8s]#

这个问题我能想到的原因是不是从没有kube-proxy服务的节点上访问Cluster IP了呢?  Kubernetes有3个⽐较容易混的IP地址:Pod IP、Cluster IP和Public IP。  Pod IP是Pod当中那个pause容器所属的IP地址,是Docker分配的,只对容器所在节点有意义,不过对于有些⽹络类型,⽐如Flannel下的k8s集群,Pod IP是在整个集群内可以访问的。Cluster IP是Kube-proxy进程通过操作IPTables虚拟出来的IP地址,在所有运⾏了Kube-proxy的节点上可以访问,实际上也就是在k8s集群的Node节点上才可以访问到。  Public IP是使⽤了Loadbalance类型的Service才具有的,是k8s⾃动调⽤云平台API⽣成的⼀个IP地址,这个在我们的视频⾥没有讲,实际⽤的也不多,现在基本上被Ingress替代了。然后如果Cluster IP不能访问,⾸先确认访问这个IP地址的节点上有没有运⾏kube-proxy进程,如果确实运⾏了依然⽆法访问,在创建服务的时候检查kube-proxy的⽇志是否有不正常的输出。可以启动kube-proxy进程的时候⽤ —v=5 参数让服务打印详细⼀些的⽇志出来。

2. k8s集群搭建好之后,部署应⽤,发现启动成功后,⼀会⼜失败,看⽇志显示链接数据库错误,但是⽤docker独⽴启动,成功,mysql客户端链接也能成功,为什么部署到k8s集群中就启动不了呢?

⽇志如下:

Caused by: java.net.UnknownHostException:
 rm-uf6919255w6al0w74.mysql.rds.aliyuncs.com:
 unknown error
 at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method) ~[na:1.8.0_66]
 at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:928) ~[na:1.8.0_66]
 at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1323) ~[na:1.8.0_66]
 at java.net.InetAddress.getAllByName0(InetAddress.java:1276) ~[na:1.8.0_66]
 at java.net.InetAddress.getAllByName(InetAddress.java:1192) ~[na:1.8.0_66]
 at java.net.InetAddress.getAllByName(InetAddress.java:1126) ~[na:1.8.0_66]
 at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:249) ~[mysqlconnector-java-5.1.25.jar!/:na]
 at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:307) ~[mysql-connector-java-5.1.25.jar!/:na]
 ... 116 common frames omitted
[root@ip-10-25-36-47 system]# mysql -h rm-uf6919255w6al0w74.mysql.rds.aliyuncs.com -u 
ddtester
 ERROR 1045 (28000): Authentication Failed For RDS maybe username or password is incorrect
[root@ip-10-25-36-47 system]# mysql -h rm-uf6919255w6al0w74.mysql.rds.aliyuncs.com -u
ddtester –p
 Enter password:
 Welcome to the MariaDB monitor. Commands end with ; or \g.
 Your MySQL connection id is 34264475 Server version: 5.6.29 Source distribution
 Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.
 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 MySQL [(none)]> exit

从错误信息看是域名没有解析成功,问题像是出在kube-dns这个服务上⾯(如果部署了的话)。  如果使⽤了kube-dns服务以后,通过k8s启动的容器会使⽤kube-dns作为它的域名解析服务器。kubedns存储了k8s中每个服务和Pod的域名,如果⽤户查询的域名不是集群内的,它会去找upstream的服务器,这个upstream服务器现在是⾃动从kube-dns容器所在的那个主机上的/etc/resolv.conf⽂件获取的。(有⼈提了PullRequest增加⼈⼯指定DNS服务器的功能,但⽬前还未合并到主⼲,https://github.com/kubernetes/dns/pull/28)  ⽽普通的容器默认是使⽤和容器所在主机⼀致的dns服务器,或是dockerd后台进程启动时“--dns”参数指定的dns服务器。  请检查通过docker直接启动的容器,和通过k8s启动的容器,其中的/etc/resolv.conf⽂件内容是否⼀致。若不⼀致,可以尝试删除kube-dns插件,重新创建⼀次。

3. k8s集群搭建成功,kubectl get node也正常,看systemctl status kube-scheduler 状态为running,⽇志中却有:

Failed to list *api.Service: Get https://ip-10-28-64-205:6443/api/v1/services?resourceVersion=0:
dial tcp 10.28.64.205:6443: getsockopt: connection refused。

请问⽼师这⼜是为什么?

如果只是偶然的⼀个错误提⽰⼤可忽略,GET /api/v1/services 这个⼊⼜只是⼀次查询操作,可能是kube-apiserver服务当时还未完全启动或⼀个临时性的错误,确认⼀下 kube-schedular 服务是否正常⼯作,如果正常就不必在意。如果kube-scheduler反复报这样的错误,那么需要检查kube-apiserver服务是否有问题了。

4. 在搭建k8s集群的时候,如果证书⽣成⽤master主机名即可构建成功,如果换成域名就报错,错误。信息如下:

https://k8smaster.fragment.com.cn:6443/api/v1/configmaps?resourceVersion=0: dial tcp139.224.226.87:6443: getsockopt: connection refused. 请问⽼师这是哪⾥配置不对吗?都是按照视频操作步骤执⾏的。

如果⽣成证书是⽤的主机名,访问时候⽤域名是不⾏的。但如果⽣成证书时候就是⽤的域名,但是使⽤域名不能访问就要具体调查了。  证书的签名是和域名绑定的,主机名在这个场景下本质上也算做是当域名⽤的(需要被DNS识别或加到hosts⽂件,否则不会解析)。不能绑定IP地址,这是SSL签名的约定。如果后⾯访问k8s服务希望⽤特定的域名,或主机名,那么⽣成服务端证书时候就要绑这个域名,如果确实绑定域名是正确的,还是不能访问,那就要具体问题具体检查了。

5. 在docker、k8s中,TLS配置差异? ?

docker和k8s的tls配置没有本质差异哈。  都是先需要CA证书(可以⾃⼰⽣成,⾃⼰⽣成的CA做的密钥就是⾃签名的,在内⽹可以⽤),然后基于CA证书⽣成服务端的公钥密钥,和客户端的公钥密钥。  Docker的TLS可以看它的⽂档:https://docs.docker.com/engine/security/https/。  Kubernetes的TLS推荐@漠然 同学的博客:https://mritd.me/2016/09/11/kubernetes-双向-TLS-配置/。证书啥的 如果整不太明⽩的话可以看下这个 https://world.taobao.com/item/533052244798.htm?  spm=a312a.7700714.0.0.R55AFw#detail 。  两者的差异只是在谁做服务端,谁做客户端⽽已。k8s⾥⾯kube-apiservice是服务端,其余服务和CLI都算客户端。docker swarm mode⾥⾯,dockerd是服务端,docker是客户端。

在docker中,man⼿册与docs⽂档,如何选择?

Docker学习的话,如果不介意英语,建议看官⽅docs,图⽂并茂的挺不错。

在CI/CD中,jenkins⼊⻔⽅式是什么?

如果确实需要使⽤,我推荐两篇⽂章。  官⽅的教程:  https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md  ⼀篇介绍⾮常详细的博客:  https://wilsonmar.github.io/jenkins2-pipeline/  但和我在视频⾥⾯讲的⼀样,Jenkins并不是CI/CD的唯⼀选择哦,看情况是不是要选

CoreOS于Rancher区别是什么?

前者是⼀个Linux发⾏版,主推的是安全和产品级的系统平滑升级。  后者是⼀个容器平台,Rancher有⼀个⾃⼰的Linux发⾏版叫RancherOS,主打的特性是轻量级。两者都是对容器⼗分友好的系统。

k8s联邦集群是什么,会有⼩节视频吗?

联邦集群是由k8s集群构成的更⼤集群,这部分在k8s 1.4以后变化⽐较⼤,还没时间去了解。在我⾃⼰做过的基于k8s⽅案⾥⾯也还没⽤过这⽅⾯的,只有在特⼤型集群(>2000节点,>120000容器)才会有这种需求。

6. Docker与微服务的关系 是不是mysql,redis这些组件都应该单独⼀个容器吗?

与微服务关系,前者是服务隔离和部署的⼯具,后者是⼀种架构,这种架构的实施通常借助Docker⽐较容易实现。  是否应该单独容器,简单的回答是:“是的”。建议条件允许的话,就每个服务单独数据库,⽅便服务独⽴演进。但如果你能确保团队能⼒OK,服务之间肯定不会通过数据库进⾏信息交换的话,即使在同⼀个mysql单独建数据库也是可以的。

7. k8s部署类似elasticsearch或者cassandra,kubectl create -f yaml后,运⾏⼀段时间有⼀定数据,想修改写参数,怎么重启呀;

kuberctl delete -f 后,再kubectl create -f,容器能不能⾃动到之前部署的节点?

如果确实怕漂移⾛,可以修改yaml⽂件,⽤Node Selectors锁定部署的⽬标节点,然后kubectl apply升级即可,顺便就把服务参数也改了。

9. 好像kubelet有⼀个临时⽬录,不⼩⼼误删会出错,这些⽬录主要⽤途?

是哪个临时⽬录呢?

kubelet默认使⽤/var/lib/kubelet⽬录存储⼀些状态数据,但这个⽬录不算是临时⽬录。

10. marathon 在关闭退出后,经过⼀段时间,通过其启动部署的docker 容器也⾃动关闭退出。请问有解决办法么?

是否可以设置为即使marathon关闭,仍然保留已启动部署的docker容器可以正常运⾏。  提问同学说已经解决了。但这个场景我确实没遇到过,如果确实需要可以让marathon使⽤mesos容器,然后在⾥⾯调⽤docker服务来起动docker容器,只是这样有点多此⼀举。  但不知为何需要在marathon关闭以后继续保持它部署的docker继续运⾏,是否有更简便的⽅式替代这种做法?

11. docker logs -f 查看的docker ⽇志总是从最开始显示,不知道这是否会占⽤docker 容器的存储?

是否能够配置指定直接存储到⽂件,以保证即使容器被删也能够查询⽇志?  不占容器存储,⽇志默认是以json⽂件格式存在容器外⾯的主机⽬录上的。  在 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log 这个位置。  默认就是存到⽂件的,但是容器删除⽇志会丢,可以考虑统⼀收集存储,⽐如ELK或者Fluentd可以做这个。

12. 通过docker network ls 查看docker的⽹络模式,但是和centos 7系统中的ip addr 显示的信息⽆法对应上,不知道如何查询或配置修改?

⽐如ip addr 中有eth0 和eth1,希望host模式或bridge模式下选择配置到eth0或eth1,请问如何配置?

“host模式”这个已经是⽐较⽼版本(1.9以前)的叫法,现在的host⽹络也是⼀个docker的network驱动类型,在host的⽹络下容器⾥看到的⽹卡和主机是⼀样的,如果主机有eth0和eth1,那么在容器⾥⾯也同样可以看到这两个⽹卡。在bridge类型的⽹络中,默认的docker0会和eth0桥接,如果是⾃⼰新创建的bridge容器⽹卡,可以⽤“--gateway”参数指定到主机eth1的地址,创建的⽹卡就会使⽤eth1作为出⼝。