TLDR

  • kubernetes的版本为1.9.4,使用kubeadm安装,3个master;
  • 涉及组件包括:kube-apiserver、etcd、kubelet、docker以及Kibana、Prometheus;

    kube-apiserver

    kubernetes集群中存在ClusterRoleBinding open-api ,导致所有匿名访问都具有cluster-admin权限,即kube-apiserver的接口可以被随意访问。
    1. apiVersion: rbac.authorization.k8s.io/v1
    2. kind: ClusterRoleBinding
    3. metadata:
    4. name: open-api
    5. namespace: ""
    6. roleRef:
    7. apiGroup: rbac.authorization.k8s.io
    8. kind: ClusterRole
    9. name: cluster-admin
    10. subjects:
    11. - apiGroup: rbac.authorization.k8s.io
    12. kind: User
    13. name: system:anonymous

    etcd

    etcd未使用TLS证书,直接向外暴露http服务。etcd支持同时监听http和https 👍

    生成证书

    可以使用openssl生成证书。本文使用sigma的kpki。
    PS:使用Linux物理机生成时会存在文件权限问题,更改为Mac后无类似问题。 ```

    生成根证书

    ./kpki root —target ./etcd

etcd每个节点生成相应证书。

由于etcd前面有一个LB,故需要将此LB添加到serve-addr参数。

./kpki etcd —ca-cert ./etcd/etcd-ca.crt —ca-key ./etcd/etcd-ca.key —peer-addr={ETCD_IP1} —serve-addr=127.0.0.1 —serve-addr={ETCD_IP1} —serve-addr={ETCD_LB} —target=./{ETCD_IP1}

etcd-ca.key需要妥善保管。以后替换新member需要使用该root证书生成新的member证书,建议拷贝到对应集群上。

cp ./etcd/etcd-ca.key ./{ETCD_IP1}/ca.key

  1. <a name="psXT1"></a>
  2. #### 拷贝证书到对应机器
  3. - 将上述target目录里的内容分别拷贝到对应机器的 `/etc/kubernetes/pki/etcd` dir;
  4. - 将etcd目录里`ca.crt` `client.crt` `client.key` 三个文件拷贝到对应机器的 `/etc/kubernetes/pki` dir,并 rename 成 `etcd-ca.crt` `apiserver-etcd-client.crt` `apiserver-etcd-client.key`
  5. <a name="w2zVZ"></a>
  6. #### 停止kube-controller-manager
  7. 为了防止在升级过程中业务 Pod 发生被 evict 行为,需要停止kube-controller-manager。master节点都要执行。这个步骤相当关键,请**务必重视,**血泪教训**。**

mv /etc/kubernetes/manifests/kube-controller-manager.yaml /etc/kubernetes/

  1. 观察到kube-controller-manager pod都消失了,再执行下面的步骤
  2. <a name="869119ce"></a>
  3. #### 逐个升级 Member URL 成 https
  4. - 升级前的etcd.yaml

spec: containers:

这个千万不要写错,仔细review 一下

$ ETCDCTL_API=3 etcdctl member update xxxx1 —peer-urls=https://{ETCD_IP1}:2380

  1. - 3member重复上面的步骤,做完之后的结果

$ ETCDCTL_API=3 etcdctl member list xxxx1, started, etcd1, https://{ETCD_IP1}:2380, http://{ETCD_IP1}:2379,https://{ETCD_IP1}:2379 xxxx2, started, etcd2, https://{ETCD_IP2}:2380, http://{ETCD_IP2}:2379,https://{ETCD_IP2}:2379 xxxx3, started, etcd3, https://{ETCD_IP3}:2380, http://{ETCD_IP3}:2379,https://{ETCD_IP3}:2379

  1. <a name="j7uCU"></a>
  2. #### 修改kube-apiserver使用TLS证书访问etcd

改成 https

  • —etcd-servers=https://{ETCD_LB}:2379

    新增三个 cmd

  • —etcd-cafile=/etc/kubernetes/pki/etcd-ca.crt
  • —etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
  • —etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key ```

    关闭etcd非TLS端口

  • 修改后的etcd.yaml

    1. spec:
    2. containers:
    3. - name: ecd1
    4. command:
    5. - etcd
    6. - --name=etcd1
    7. ### 去掉两个 http
    8. - --listen-client-urls=https://{ETCD_IP1}:2379,https://127.0.0.1:2379
    9. ### 去掉 http
    10. - --advertise-client-urls=https://{ETCD_IP1}:2379
    11. - --listen-peer-urls=https://{ETCD_IP1}:2380
    12. - --initial-advertise-peer-urls=https://{ETCD_IP1}:2380
    13. ...
    14. ### 修改 livenessProbe
    15. livenessProbe:
    16. exec:
    17. command:
    18. - /bin/sh
    19. - -ec
    20. - ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379
    21. --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/client.crt
    22. --key=/etc/kubernetes/pki/etcd/client.key get foo
    23. failureThreshold: 8
    24. initialDelaySeconds: 60
    25. periodSeconds: 10
    26. successThreshold: 1
    27. timeoutSeconds: 15
  • 在3个节点重复执行,就需要tls访问了

    1. $ ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/client.crt --key=/etc/kubernetes/pki/etcd/client.key member list
    2. xxxx1, started, etcd1, https://{ETCD_IP1}:2380, https://{ETCD_IP1}:2379
    3. xxxx2, started, etcd2, https://{ETCD_IP2}:2380, https://{ETCD_IP2}:2379
    4. xxxx3, started, etcd3, https://{ETCD_IP3}:2380, https://{ETCD_IP3}:2379

    恢复kube-controller-manager

    1. mv /etc/kubernetes/kube-controller-manager.yaml /etc/kubernetes/manifests/kube-controller-manager.yaml

    Prometheus

    增加TLS认证后,Prometheus无法匿名访问k8集群。访问kubelet和etcd需要适配。

    kubelet

    kubelet启动参数加上 --authentication-token-webhook=true

    1. sudo vim /etc/systemd/system/kubelet.service.d/10-kubeadm.conf KUBELET_AUTHZ_ARGS=--authentication-token-webhook=true
    2. sudo systemctl daemon-reload
    3. sudo systemctl restart kubelet

    Prometheus采集kubelet metrics的时候其实是带了ServiceAccount Token,如果kubelet没开启这个参数就会把这个Token忽略了。开启这个参数之后,kubelet会将这个Token使用TokenReview的方式forward给kube-apiserver去获取Token代表的User。

    etcd

    Prometheus Operator 监控 etcd 集群

    Docker

    dockerd 启动参数去掉 --host=tcp://0.0.0.0:2375。去掉之后没影响,kubelet使用unix socket访问 docker,可以放心的去掉这个参数 ``` $ sudo vim /usr/lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd

修改成

ExecStart=/usr/bin/dockerd —host=unix:///var/run/docker.sock

$ sudo systemctl enable docker $ sudo systemctl restart docker ```

Kibana

xpack改造成本较高,采用kibana前面挂载一个nginx服务,让nginx做basic auth认证。Nginx Ingress是最为简单的实现方式。