K8S入门系列之二进制部署(二)

kubernetes-1.14.2所需组件及其版本

Kubernetes: v1.14.2
Docker: 18.09.4
Etcd: v3.3.12
Flannel: v0.11.0
cni-plugins: v0.7.5
CoreDNS: 1.4.0 

所有组件下载地址

k8s各版本组件下载地址:

https://github.com/kubernetes/kubernetes/tree/v1.14.2

组件下载

https://storage.googleapis.com/kubernetes-release/release/v1.14.2/kubernetes-node-linux-amd64.tar.gz
https://storage.googleapis.com/kubernetes-release/release/v1.14.2/kubernetes-server-linux-amd64.tar.gz
https://storage.googleapis.com/kubernetes-release/release/v1.14.2/kubernetes-client-linux-amd64.tar.gz
https://storage.googleapis.com/kubernetes-release/release/v1.14.2/kubernetes.tar.gz

cfssl download

https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64

etcd、flannel、cni-plugins

https://github.com/etcd-io/etcd/releases/download/v3.3.12/etcd-v3.3.12-linux-amd64.tar.gz
https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
https://github.com/containernetworking/plugins/releases/download/v0.7.5/cni-plugins-amd64-v0.7.5.tgz

kubernetes内部需要5套证书,手动创建或者自动生成,分别为:
  1. etcd内部通信需要一套ca和对应证书。
  2. etcd与外部通信也要有一套ca和对应证书。
  3. APIserver间通信需要一套证书。
  4. apiserver与node间通信需要一套证书。
  5. node和pod间通信需要一套ca证书。
Kubernetes的三种IP:

1.Node IP:Node节点的IP地址
2.Pod IP: Pod的IP地址
3.Cluster IP:Service的IP地址

注:
-> Node IP是Kubernetes集群中节点的物理网卡IP地址,所有属于这个网络的服务器之间都能通过这个网络直接通信。这也表明Kubernetes集群之外的节点访问Kubernetes集群之内的某个节点或者TCP/IP服务的时候,必须通过Node IP进行通信

-> Pod IP是每个Pod的IP地址,他是Docker Engine根据docker0网桥的IP地址段进行分配的,通常是一个虚拟的二层网络。

-> Cluster IP是一个虚拟的IP,但更像是一个伪造的IP网络,原因有以下几点:
-> Cluster IP仅仅作用于Kubernetes Service这个对象,并由Kubernetes管理和分配P地址
-> Cluster IP无法被ping,他没有一个“实体网络对象”来响应
-> Cluster IP只能结合Service Port组成一个具体的通信端口,单独的Cluster IP不具备通信的基础,并且他们属于Kubernetes集群这样一个封闭的空间。

-> Kubernetes集群之内,Node IP网、Pod IP网于Cluster IP网之间的通信,采用的是Kubernetes自己设计的一种编程方式的特殊路由规则。

一、系统基本环境初始化

1.1、系统基础环境

[root@localhost ~]# cat /etc/redhat-release 
CentOS Linux release 7.6.1810 (Core) 

1.2、关闭firewall(初始配置先关闭,安全需要配置完成再打开!)

[root@localhost ~]# systemctl disable firewalld && systemctl stop firewalld

1.3、关闭selinux并重启机器

[root@localhost ~]# vi /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled                                                       
# SELINUXTYPE= can take one of three two values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

1.4、关闭swap

[root@localhost ~]# vi /etc/fstab 

# /etc/fstab
# Created by anaconda on Tue Jun 25 16:01:12 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=391d02ff-bb33-467e-931b-d3e050c116c5 /boot                   xfs     defaults        0 0
/dev/mapper/centos-home /home                   xfs     defaults        0 0
# /dev/mapper/centos-swap swap                    swap    defaults        0 0                         #注释掉挂载swap的行~~

1.5、设置系统时区和时间同步

设置系统时区

[root@localhost ~]# timedatectl set-timezone Asia/Shanghai
[root@localhost ~]# timedatectl set-local-rtc 0

时间同步

[root@localhost ~]# yum install ntpdate -y

[root@localhost ~]# ntpdate cn.pool.ntp.org

二、K8S集群环境初始化

2.1、k8s集群机器规划

192.168.1.201 kube-master01
192.168.1.202 kube-master02
192.168.1.203 kube-master03

2.2、设置永久机器名,分别执行:

[root@localhost ~]# hostnamectl set-hostname kube-master01
[root@localhost ~]# hostnamectl set-hostname kube-master02
[root@localhost ~]# hostnamectl set-hostname kube-master03

2.3、修改 /etc/hostname 文件,添加主机名和 IP 的对应关系

[root@localhost ~]# vi /etc/hosts
192.168.1.201 kube-master01
192.168.1.202 kube-master02
192.168.1.203 kube-master03

2.4、添加 k8s 和 docker 账户

在每台机器上添加k8s账户并设置密码

[root@kube-master01 ~]# useradd -m k8s
[root@kube-master01 ~]# passwd k8s
......

将k8s用户归到wheel组

[root@kube-master01~]# gpasswd -a k8s wheel

在每台机器上添加 docker 账户,将 k8s 账户添加到 docker 组中,同时配置 dockerd 参数(注:安装完docker才有):

[root@kube-master01 ~]# useradd -m docker
[root@kube-master01 ~]# gpasswd -a k8s docker
[root@kube-master01 ~]# mkdir -p /opt/docker/

[root@kube-master01 ~]# vim /opt/docker/daemon.json
{

  "registry-mirrors": ["https://hub-mirror.c.163.com", "https://docker.mirrors.ustc.edu.cn"],

  "max-concurrent-downloads": 20

}

2.5、无密码登录其它节点:

生成密钥对:

[root@kube-master01 ~]# ssh-keygen

将自己的公钥发给其它节点:

[root@kube-master01 ~]# ssh-copy-id root@kube-master01
[root@kube-master01 ~]# ssh-copy-id root@kube-master02
[root@kube-master01 ~]# ssh-copy-id root@kube-master03
[root@kube-master01 ~]# ssh-copy-id k8s@kube-master01
[root@kube-master01 ~]# ssh-copy-id k8s@kube-master02
[root@kube-master01 ~]# ssh-copy-id k8s@kube-master03

2.6、将可执行文件路径 /opt/k8s/bin 添加到 PATH 变量

[root@kube-master01 ~]# sh -c "echo 'PATH=/opt/k8s/bin:$PATH:$HOME/bin:$JAVA_HOME/bin' >> /etc/profile.d/k8s.sh"
[root@kube-master01 ~]# source /etc/profile.d/k8s.sh 

2.7、加载内核模块

[root@kube-master01 ~]# modprobe br_netfilter
[root@kube-master01 ~]# modprobe ip_vs

2.8、设置系统参数

[root@kube-master01 ~]# cat > kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720

[root@kube-master01 ~]# mv ./kubernetes.conf /etc/sysctl.d/kubernetes.conf
[root@kube-master01 ~]# sysctl -p /etc/sysctl.d/kubernetes.conf
[root@kube-master01 ~]# mount -t cgroup -o cpu,cpuacct none /sys/fs/cgroup/cpu,cpuacct

注:
tcp_tw_recycle 和 Kubernetes 的 NAT 冲突,必须关闭 ,否则会导致服务不通;
关闭不使用的 IPV6 协议栈,防止触发 docker BUG;

2.9、安装依赖包

[root@kube-master01 ~]# yum install epel-release -y
[root@kube-master01 ~]# yum install -y conntrack ipvsadm ipset jq sysstat curl iptables libseccomp net-tools

目录预建立

[root@kube-master01 ~]# mkdir -p /opt/k8s/bin
[root@kube-master01 ~]# mkdir -p /opt/k8s/cert
[root@kube-master01 ~]# mkdir -p /opt/etcd/cert
[root@kube-master01 ~]# mkdir -p /opt/lib/etcd
[root@kube-master01 ~]# mkdir -p /opt/k8s/script
[root@kube-master01 ~]# chown -R k8s /opt/*

以上在所有节点执行!

三、创建CA证书和密钥(cfssl)

3.1、安装 cfssl 工具集

[root@kube-master01 k8s]# mkdir -p /opt/k8s/cert && chown -R k8s /opt/k8s && cd /opt/k8s/bin/
[root@kube-master01 k8s]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
[root@kube-master01 bin]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
[root@kube-master01 bin]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64

[root@kube-master01 bin]# chmod +x /opt/k8s/bin/*

为方便操作--改名(可不做更改,但使用命令的时候补全命令!!)

[root@kube-master01 bin]# mv cfssl-certinfo_linux-amd64 cfssl-certinfo
[root@kube-master01 bin]# mv cfssl_linux-amd64 cfssl
[root@kube-master01 bin]# mv cfssljson_linux-amd64 cfssljson

3.2、创建根证书(CA)

CA 证书是集群所有节点共享的,只需要创建一个 CA 证书,后续创建的所有证书都由它签名。

创建配置文件

CA 配置文件用于配置根证书的使用场景 (profile) 和具体参数 (usage,过期时间、服务端认证、客户端认证、加密等),后续在签名其它证书时需要指定特定场景。

[root@kube-master01 ~]# cd /opt/k8s/cert

[root@kube-master01 cert]# vim ca-config.json
{
    "signing": {
        "default": {
            "expiry": "87600h"
        },
        "profiles": {
            "kubernetes": {
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth",
                    "client auth"
                ],
                "expiry": "87600h"
            }
        }
    }
}

注:
① signing :表示该证书可用于签名其它证书,生成的 ca.pem 证书中CA=TRUE ;
② server auth :表示 client 可以用该该证书对 server 提供的证书进行验证;
③ client auth :表示 server 可以用该该证书对 client 提供的证书进行验证;

创建证书签名请求文件
[root@kube-master01 cert]# vim ca-csr.json
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "k8s",
            "OU": "4Paradigm"
        }
    ]
}

注:
① CN: Common Name ,kube-apiserver 从证书中提取该字段作为请求的用户名(User Name),浏览器使用该字段验证网站是否合法;
② O: Organization ,kube-apiserver 从证书中提取该字段作为请求用户所属的组(Group);
③ kube-apiserver 将提取的 User、Group 作为 RBAC 授权的用户标识;

生成 CA 证书和私钥
[root@kube-master01 cert]# cfssl_linux-amd64 gencert -initca ca-csr.json | cfssljson_linux-amd64 -bare ca

[root@kube-master01 cert]# ls
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem

#### 分发证书文件
将生成的 CA 证书、秘钥文件、配置文件拷贝到所有节点的/opt/k8s/cert 目录下:

[root@kube-master01 ~]# vim /opt/k8s/script/scp_k8scert.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p /opt/k8s/cert && chown -R k8s /opt/k8s"
    scp /opt/k8s/cert/ca*.pem /opt/k8s/cert/ca-config.json k8s@${node_ip}:/opt/k8s/cert
done

[root@kube-master01 ~]# chmod +x /opt/k8s/script/scp_k8scert.sh && /opt/k8s/script/scp_k8scert.sh

四、部署kubectl命令行工具

kubectl 是 kubernetes 集群的命令行管理工具。

kubectl 默认从 ~/.kube/config 文件读取 kube-apiserver 地址、证书、用户名等信息。

4.1、下载kubectl二进制文件

[root@kube-master01 ~]# wget https://dl.k8s.io/v1.14.2/kubernetes-client-linux-amd64.tar.gz      ## 换源或?  你懂得!

[root@kube-master01 ~]# tar -xzvf ./kubernetes-client-linux-amd64.tar.gz

[root@kube-master01 ~]# cp ./kubernetes/client/bin/kubectl /opt/k8s/bin/                             # 咱有设置好的环境变量目录

4.2、创建 admin 证书和私钥

kubectl 与 apiserver https 安全端口通信,apiserver 对提供的证书进行认证和授权。
kubectl 作为集群的管理工具,需要被授予最高权限。这里创建具有最高权限的admin 证书。

创建证书签名请求
[root@kube-master01 ~]# cd /opt/k8s/cert/

[root@kube-master01 cert]# cat > kubectl-csr.json <<EOF
{
    "CN": "kubectl",
    "hosts": [],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "system:masters",
            "OU": "4Paradigm"
        }
    ]
}

注:
① O 为 system:masters ,kube-apiserver 收到该证书后将请求的 Group 设置为system:masters;
② 预定义的 ClusterRoleBinding cluster-admin 将 Group system:masters 与Role cluster-admin 绑定,该 Role 授予所有 API的权限;
③ 该证书只会被 kubectl 当做 client 证书使用,所以 hosts 字段为空;

生成证书和私钥
[root@kube-master01 cert]# cfssl_linux-amd64 gencert -ca=/opt/k8s/cert/ca.pem -ca-key=/opt/k8s/cert/ca-key.pem -config=/opt/k8s/cert/ca-config.json -profile=kubernetes kubectl-csr.json | cfssljson_linux-amd64 -bare kubectl

验证:

[root@kube-master01 cert]#  ls kubectl*
kubectl.csr  kubectl-csr.json  kubectl-key.pem  kubectl.pem

4.3、创建和分发/root/.kube/config 文件

创建kubeconfig文件

kubeconfig 为 kubectl 的配置文件,包含访问 apiserver 的所有信息,如 apiserver 地址、CA 证书和自身使用的证书;

① 设置集群参数,(--server=${KUBE_APISERVER} ,指定IP和端口;如果没有haproxy代理,就用实际服务器的IP及端口;如果有就用haproxy的VIP和端口,高可用!)

[root@kube-master01~]# kubectl config set-cluster kubernetes --certificate-authority=/opt/k8s/cert/ca.pem --embed-certs=true --server=https://192.168.1.101:8443 --kubeconfig=/root/.kube/config

② 设置客户端认证参数

[root@kube-master01 ~] kubectl config set-credentials kube-admin --client-certificate=/opt/k8s/cert/kubectl.pem --client-key=/opt/k8s/cert/kubectl-key.pem --embed-certs=true --kubeconfig=/root/.kube/config

③ 设置上下文参数

[root@kube-master01 ~]# kubectl config set-context kube-admin@kubernetes --cluster=kubernetes --user=kube-admin --kubeconfig=/root/.kube/config

④ 设置默认上下文

[root@kube-master ~]# kubectl config use-context kube-admin@kubernetes --kubeconfig=/root/.kube/config

注:
--certificate-authority :验证 kube-apiserver 证书的根证书;
--client-certificate 、 --client-key :刚生成的 admin 证书和私钥,连接 kube-apiserver 时使用;
--embed-certs=true :将 ca.pem 和 admin.pem 证书内容嵌入到生成的kubectl.kubeconfig 文件中(不加时,写入的是证书文件路径);

验证kubeconfig文件
[root@kube-master01 ~]# ls /root/.kube/config
/root/.kube/config
[root@kube-master01 ~]# kubectl config view --kubeconfig=/root/.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: https://192.168.1.101:8443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kube-admin
  name: kube-admin@kubernetes
current-context: kube-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kube-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
分发 kubeclt 和kubeconfig 文件,分发到所有使用kubectl 命令的节点
[root@kube-master01 ~]# vim /opt/k8s/script/scp_kubectl.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    scp /root/kubernetes/client/bin/kubectl k8s@${node_ip}:/opt/k8s/bin/
    ssh k8s@${node_ip} "chmod +x /opt/k8s/bin/*"
    ssh k8s@${node_ip} "mkdir -p ~/.kube"
    scp ~/.kube/config k8s@${node_ip}:~/.kube/config
    ssh root@${node_ip} "mkdir -p ~/.kube"
    scp ~/.kube/config root@${node_ip}:~/.kube/config
done


[root@kube-master01 ~]# chmod +x /opt/k8s/script/scp_kubectl.sh && /opt/k8s/script/scp_kubectl.sh             #  有强迫症的把mstaer01 的IP删掉,没有的无视掉报错,哈哈!

五、部署 etcd 集群

etcd 是基于 Raft 的分布式 key-value 存储系统,由 CoreOS 开发,常用于服务发现、共享配置以及并发控制(如 leader 选举、分布式锁等)。
kubernetes 使用 etcd 存储所有运行数据。

本文档介绍部署一个三节点高可用 etcd 集群的步骤:
① 下载和分发 etcd 二进制文件
② 创建 etcd 集群各节点的 x509 证书,用于加密客户端(如 etcdctl) 与 etcd 集群、etcd 集群之间的数据流;
③ 创建 etcd 的 systemd unit 文件,配置服务参数;
④ 检查集群工作状态;

5.1、下载etcd 二进制文件

到 https://github.com/coreos/etcd/releases 页面下载最新版本的发布包:

[root@kube-master01 ~]# https://github.com/etcd-io/etcd/releases/download/v3.3.12/etcd-v3.3.12-linux-amd64.tar.gz
[root@kube-master01 ~]# tar -xvf etcd-v3.3.12-linux-amd64.tar.gz 

5.2、创建 etcd 证书和私钥

创建证书签名请求
[root@kube-master01 ~]# cd /opt/etcd/cert/

[root@kube-master01 cert]# cat > etcd-csr.json <<EOF
{
    "CN": "etcd",
    "hosts": [
        "127.0.0.1",
        "192.168.1.201",
        "192.168.1.202",
        "192.168.1.203"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "k8s",
            "OU": "4Paradigm"
        }
    ]
}

注:hosts 字段指定授权使用该证书的 etcd 节点 IP 或域名列表,这里将 etcd 集群的三个节点 IP 都列在其中;

生成证书和私钥
[root@kube-master01 cert]# cfssl_linux-amd64 gencert -ca=/opt/k8s/cert/ca.pem -ca-key=/opt/k8s/cert/ca-key.pem -config=/opt/k8s/cert/ca-config.json -profile=kubernetes etcd-csr.json | cfssljson_linux-amd64 -bare etcd

验证:

[root@kube-master01 cert]# ls etcd*
etcd.csr  etcd-csr.json  etcd-key.pem  etcd.pem
分发生成的证书和私钥以及etcd的二进制文件到各 etcd 节点
[root@kube-master01 cert]# vim /opt/k8s/script/scp_etcd.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")

for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        scp /root/etcd-v3.3.12-linux-amd64/etcd* k8s@${node_ip}:/opt/k8s/bin
        ssh k8s@${node_ip} "chmod +x /opt/k8s/bin/*"
        ssh root@${node_ip} "mkdir -p /opt/etcd/cert && chown -R k8s /opt/etcd/cert"
        scp /opt/etcd/cert/etcd*.pem k8s@${node_ip}:/opt/etcd/cert/
done

分发到etcd的个节点

[root@kube-master01 cert]# chmod +x /opt/k8s/script/scp_etcd.sh && /opt/k8s/script/scp_etcd.sh

5.3、创建etcd 的systemd unit 模板及etcd 配置文件

创建etcd 的systemd unit 模板
[root@kube-master01 cert]# vim /opt/etcd/etcd.service.template

[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
User=k8s
Type=notify
WorkingDirectory=/opt/lib/etcd/
ExecStart=/opt/k8s/bin/etcd \
    --data-dir=/opt/lib/etcd \
    --name ##NODE_NAME## \
    --cert-file=/opt/etcd/cert/etcd.pem \
    --key-file=/opt/etcd/cert/etcd-key.pem \
    --trusted-ca-file=/opt/k8s/cert/ca.pem \
    --peer-cert-file=/opt/etcd/cert/etcd.pem \
    --peer-key-file=/opt/etcd/cert/etcd-key.pem \
    --peer-trusted-ca-file=/opt/k8s/cert/ca.pem \
    --peer-client-cert-auth \
    --client-cert-auth \
    --listen-peer-urls=https://##NODE_IP##:2380 \
    --initial-advertise-peer-urls=https://##NODE_IP##:2380 \
    --listen-client-urls=https://##NODE_IP##:2379,http://127.0.0.1:2379\
    --advertise-client-urls=https://##NODE_IP##:2379 \
    --initial-cluster-token=etcd-cluster-0 \
    --initial-cluster=etcd01=https://192.168.1.201:2380,etcd02=https://192.168.1.202:2380,etcd03=https://192.168.1.203:2380 \
    --initial-cluster-state=new
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

注:
User :指定以 k8s 账户运行;
WorkingDirectory 、 --data-dir :指定工作目录和数据目录为/opt/lib/etcd ,需在启动服务前创建这个目录;
--name :指定节点名称,当 --initial-cluster-state 值为 new 时, --name 的参数值必须位于 --initial-cluster 列表中;
--cert-file 、 --key-file :etcd server 与 client 通信时使用的证书和私钥;
--trusted-ca-file :签名 client 证书的 CA 证书,用于验证 client 证书;
--peer-cert-file 、 --peer-key-file :etcd 与 peer 通信使用的证书和私钥;
--peer-trusted-ca-file :签名 peer 证书的 CA 证书,用于验证 peer 证书;

5.4、为各节点创建和分发 etcd systemd unit 文件

[root@kube-master01 cert]# cd /opt/k8s/script/

[root@kube-master01 cert]# vim /opt/k8s/script/etcd_service.sh

NODE_NAMES=("etcd01" "etcd02" "etcd03")
NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
#替换模板文件中的变量,为各节点创建 systemd unit 文件
for (( i=0; i < 3; i++ ));do
        sed -e "s/##NODE_NAME##/${NODE_NAMES[i]}/g" -e "s/##NODE_IP##/${NODE_IPS[i]}/g" /opt/etcd/etcd.service.template > /opt/etcd/etcd-${NODE_IPS[i]}.service
done
#分发生成的 systemd unit 和etcd的配置文件:
for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        ssh root@${node_ip} "mkdir -p /opt/lib/etcd && chown -R k8s /opt/lib/etcd"
        scp /opt/etcd/etcd-${node_ip}.service root@${node_ip}:/etc/systemd/system/etcd.service
done

分发各节点:

[root@kube-master01 script]#  chmod +x /opt/k8s/script/etcd_service.sh && /opt/k8s/script/etcd_service.sh

验证:

[root@kube-master01 script]# ls /opt/etcd/*.service
/opt/etcd/etcd-192.168.1.201.service  /opt/etcd/etcd-192.168.1.203.service
/opt/etcd/etcd-192.168.1.202.service
[root@kube-master01 script]# ls /etc/systemd/system/etcd.service
/etc/systemd/system/etcd.service

5.5、启动 etcd 服务

[root@kube-master01 script]# vim /opt/k8s/script/etcd.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
#启动 etcd 服务
for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        ssh root@${node_ip} "systemctl daemon-reload && systemctl enable etcd && systemctl start etcd"
done
#检查启动结果,确保状态为 active (running)
for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        ssh k8s@${node_ip} "systemctl status etcd|grep Active"
done
#验证服务状态,输出均为healthy 时表示集群服务正常
for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        ETCDCTL_API=3 /opt/k8s/bin/etcdctl \
--endpoints=https://${node_ip}:2379 \
--cacert=/opt/k8s/cert/ca.pem \
--cert=/opt/etcd/cert/etcd.pem \
--key=/opt/etcd/cert/etcd-key.pem endpoint health
done 

执行脚本,启动etcd

[root@kube-master01 script]# chmod +x /opt/k8s/script/etcd.sh && /opt/k8s/script/etcd.sh
>>> 192.168.1.201
>>> 192.168.1.202
>>> 192.168.1.203
>>> 192.168.1.201
   Active: active (running) since 四 2019-08-08 18:19:01 CST; 36s ago
>>> 192.168.1.202
   Active: active (running) since 四 2019-08-08 18:19:01 CST; 36s ago
>>> 192.168.1.203
   Active: active (running) since 四 2019-08-08 18:19:07 CST; 31s ago
>>> 192.168.1.201
https://192.168.1.201:2379 is healthy: successfully committed proposal: took = 2.705585ms
>>> 192.168.1.202
https://192.168.1.202:2379 is healthy: successfully committed proposal: took = 3.410408ms
>>> 192.168.1.203
https://192.168.1.203:2379 is healthy: successfully committed proposal: took = 3.132799ms
如服务启动失败,查看日志:$ journalctl -u etcd

六、部署 flannel 网络

kubernetes 要求集群内各节点(包括 master 节点)能通过 Pod 网段互联互通。flannel 使用 vxlan 技术为各节点创建一个可以互通的 Pod 网络,使用的端口为 UDP 8472,需要开放该端口(如公有云 AWS 等)。
flannel 第一次启动时,从 etcd 获取 Pod 网段信息,为本节点分配一个未使用的 /24段地址,然后创建 flannel.1 (也可能是其它名称,如 flannel1 等) 接口。
flannel 将分配的 Pod 网段信息写入 /run/flannel/docker 文件,docker 后续使用这个文件中的环境变量设置 docker0 网桥。

6.1、下载flanneld 二进制文件

到 https://github.com/coreos/flannel/releases 页面下载最新版本的发布包:

[root@kube-master01 ~]# wget https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
[root@kube-master01 ~]# tar -xvxf flannel-v0.11.0-linux-amd64.tar.gz -C  /root/flannel/

6.2、创建 flannel 证书和私钥

flannel 从 etcd 集群存取网段分配信息,而 etcd 集群启用了双向 x509 证书认证,所以需要为 flanneld 生成证书和私钥

创建证书签名请求:
[root@kube-master01 ~]# mkdir -p /opt/flannel/cert      # 所有节点都要创建!!!
[root@kube-master01 ~]# cd /opt/flannel/cert

[root@kube-master01 cert]# cat > flanneld-csr.json <<EOF
{
    "CN": "flanneld",
    "hosts": [],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "k8s",
            "OU": "4Paradigm"
        }
    ]
}

注:该证书只会被 kubectl 当做 client 证书使用,所以 hosts 字段为空;

生成证书和私钥
[root@kube-master01 cert]# cfssl_linux-amd64 gencert -ca=/opt/k8s/cert/ca.pem -ca-key=/opt/k8s/cert/ca-key.pem -config=/opt/k8s/cert/ca-config.json -profile=kubernetes flanneld-csr.json | cfssljson_linux-amd64 -bare flanneld

验证下:

[root@kube-master01 cert]# ls
flanneld.csr  flanneld-csr.json  flanneld-key.pem  flanneld.pem
将flanneld 二进制文件和生成的证书和私钥分发到所有节点
[root@kube-master01 cert]# vim /opt/k8s/script/scp_flannel.sh 

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    scp /root/flannel/{flanneld,mk-docker-opts.sh} k8s@${node_ip}:/opt/k8s/bin/
    ssh k8s@${node_ip} "chmod +x /opt/k8s/bin/*"
    ssh root@${node_ip} "mkdir -p /opt/flannel/cert && chown -R k8s /opt/flannel"
    scp /opt/flannel/cert/flanneld*.pem k8s@${node_ip}:/opt/flannel/cert
done

分发到各节点

[root@kube-master01 ~]# chmod +x /opt/k8s/script/scp_flannel.sh && /opt/k8s/script/scp_flannel.sh 

6.3、向etcd 写入集群Pod 网段信息

分开执行就报错,咱也不懂,咱也不敢问! 哈哈(可能是etcd v3和 V2命令不同的事!)

[root@kube-master01 ~]# etcdctl --endpoints="https://192.168.1.201:2379,https://192.168.1.202:2379,https://192.168.1.203:2379" --ca-file=/opt/k8s/cert/ca.pem --cert-file=/opt/flannel/cert/flanneld.pem --key-file=/opt/flannel/cert/flanneld-key.pem set /atomic.io/network/config '{"Network":"10.30.0.0/16","SubnetLen": 24, "Backend": {"Type": "vxlan"}}'

返回结果:

{"Network":"10.30.0.0/16","SubnetLen": 24, "Backend": {"Type": "vxlan"}}

注:
flanneld 当前版本 (v0.10.0) 不支持 etcd v3,故使用 etcd v2 API 写入配置 key 和网段数据;
写入的 Pod 网段 "Network" 必须是 /16 段地址,必须与kube-controller-manager 的 --cluster-cidr 参数值一致;

6.4、创建 flanneld 的 systemd unit 文件

[root@kube-master01 ~]# cat > /opt/flannel/flanneld.service << EOF
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service

[Service]
Type=notify
ExecStart=/opt/k8s/bin/flanneld \
-etcd-cafile=/opt/k8s/cert/ca.pem \
-etcd-certfile=/opt/flannel/cert/flanneld.pem \
-etcd-keyfile=/opt/flannel/cert/flanneld-key.pem \
-etcd-endpoints=https://192.168.1.201:2379,https://192.168.1.202:2379,https://192.168.1.203:2379 \
-etcd-prefix=/atomic.io/network \
-iface=eth0   
ExecStartPost=/opt/k8s/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=on-failure

[Install]
WantedBy=multi-user.target
RequiredBy=docker.service

注:
mk-docker-opts.sh 脚本将分配给 flanneld 的 Pod 子网网段信息写入/run/flannel/docker 文件,后续 docker 启动时使用这个文件中的环境变量配置 docker0 网桥;

flanneld 使用系统缺省路由所在的接口与其它节点通信,对于有多个网络接口(如内网和公网)的节点,可以用 -iface 参数指定通信接口,如上面的 eth0 接口;(根据实际存在的网卡名称修改)

flanneld 运行时需要 root 权限;

6.5、分发flanneld systemd unit 文件到所有节点,启动并检查flanneld 服务

[root@kube-master01 ~]# vim /opt/k8s/script/flanneld_service.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
# 分发 flanneld systemd unit 文件到所有节点
    scp /opt/flannel/flanneld.service root@${node_ip}:/etc/systemd/system/
# 启动 flanneld 服务
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable flanneld && systemctl restart flanneld"
# 检查启动结果
    ssh k8s@${node_ip} "systemctl status flanneld|grep Active"
done

执行:

[root@kube-master01 ~]# chmod +x /opt/k8s/script/flanneld_service.sh && /opt/k8s/script/flanneld_service.sh

七、部署master节点

① kubernetes master 节点运行如下组件:
kube-apiserver
kube-scheduler
kube-controller-manager

② kube-scheduler 和 kube-controller-manager 可以以集群模式运行,通过 leader 选举产生一个工作进程,其它进程处于阻塞模式。

③ 对于 kube-apiserver,可以运行多个实例(本文档是 3 实例),但对其它组件需要提供统一的访问地址,该地址需要高可用。本文档使用 keepalived 和 haproxy 实现 kube-apiserver VIP 高可用和负载均衡。

④ 因为对master做了keepalived高可用,所以3台服务器都有可能会升成master服务器(主master宕机,会有从升级为主);因此所有的master操作,在3个服务器上都要进行。

下载最新版本的二进制文件并拷贝到所有 master 节点

[root@kube-master01 ~]# wget https://dl.k8s.io/v1.10.4/kubernetes-server-linux-amd64.tar.gz

[root@kube-master01 ~]# tar -zvxf kubernetes-server-linux-amd64.tar.gz 
[root@kube-master01 ~]# cd kubernetes
[root@kube-master01 kubernetes]# tar -zxvf kubernetes-src.tar.gz 

编写脚本拷贝至所有master节点

[root@kube-master01 ~]# vim /opt/k8s/script/scp_master.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    scp /root/kubernetes/server/bin/* k8s@${node_ip}:/opt/k8s/bin/
    ssh k8s@${node_ip} "chmod +x /opt/k8s/bin/*"
done

[root@kube-master01 ~]# chmod +x /opt/k8s/script/scp_master.sh && /opt/k8s/script/scp_master.sh

7.1、部署高可用组件 keepalived 和 haproxy

① 本文档讲解使用 keepalived 和 haproxy 实现 kube-apiserver 高可用的步骤:

keepalived 提供 kube-apiserver 对外服务的 VIP;
haproxy 监听 VIP,后端连接所有 kube-apiserver 实例,提供健康检查和负载均衡功能;

② 运行 keepalived 和 haproxy 的节点称为 LB 节点。由于 keepalived 是一主多备运行模式,故至少两个 LB 节点。

③ 本文档复用 master 节点的三台机器,haproxy 监听的端口(8443) 需要与 kube-apiserver的端口 6443 不同,避免冲突。

④ keepalived 在运行过程中周期检查本机的 haproxy 进程状态,如果检测到 haproxy 进程异常,则触发重新选主的过程,VIP 将飘移到新选出来的主节点,从而实现 VIP 的高可用。

⑤ 所有组件(如 kubeclt、apiserver、controller-manager、scheduler 等)都通过 VIP 和haproxy 监听的 8443 端口访问 kube-apiserver 服务。

yum安装keepalived 、haproxy
[root@kube-master01 kubernetes]# yum install keepalived haproxy -y
haproxy配置文件 /etc/haproxy/haproxy.cfg
global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /var/run/haproxy-admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon
    nbproc 1

defaults
    log global
    timeout connect 5000
    timeout client 10m
    timeout server 10m

listen admin_stats
    bind 0.0.0.0:10080
    mode http
    log 127.0.0.1 local0 err
    stats refresh 30s
    stats uri /status
    stats realm welcome login\ Haproxy
    stats auth haproxy:haproxy-2019         #界面登录帐号和密码
    stats hide-version
    stats admin if TRUE

listen kube-master
    bind 0.0.0.0:8443
    mode tcp
    option tcplog
    balance source
    server 192.168.1.201 192.168.1.201:6443 check inter 2000 fall 2 rise 2 weight 1
    server 192.168.1.202 192.168.1.202:6443 check inter 2000 fall 2 rise 2 weight 1
    server 192.168.1.203 192.168.1.203:6443 check inter 2000 fall 2 rise 2 weight 1

注:
haproxy 在 10080 端口输出 status 信息;
haproxy 监听所有接口的 8443 端口,该端口与环境变量 ${KUBE_APISERVER} 指定的端口必须一致;
server 字段列出所有kube-apiserver监听的 IP 和端口;

在其他服务器安装、下发haproxy 配置文件;并启动检查haproxy服务
[root@master ~]# vim /opt/k8s/script/haproxy.sh
-----
NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
 #安装haproxy
    ssh root@${node_ip} "yum install -y keepalived haproxy"
 #下发配置文件
    scp /etc/haproxy/haproxy.cfg root@${node_ip}:/etc/haproxy
 #启动检查haproxy服务
    ssh root@${node_ip} "systemctl restart haproxy"
 ssh root@${node_ip} "systemctl enable haproxy.service"
    ssh root@${node_ip} "systemctl status haproxy|grep Active"
 #检查 haproxy 是否监听6443 端口
    ssh root@${node_ip} "netstat -lnpt|grep haproxy"
done
[root@kube-master01 ~]# chmod +x /opt/k8s/script/haproxy.sh && /opt/k8s/script/haproxy.sh

输出类似于:

tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN 5351/haproxy

tcp 0 0 0.0.0.0:10080 0.0.0.0:* LISTEN 5351/haproxy
配置和启动 keepalived 服务

keepalived 是一主(master)多备(backup)运行模式,故有两种类型的配置文件。

master 配置文件只有一份,backup 配置文件视节点数目而定,对于本文档而言,规划如下:

master: 192.168.1.201
backup:192.168.1.202、192.168.1.203

(1)在192.168.1.201 master服务;配置文件:

[root@kube-master01 ~]# vim /etc/keepalived/keepalived.conf
-------
global_defs {
    router_id keepalived_hap
}
vrrp_script check-haproxy {
    script "killall -0 haproxy"
    interval 5
    weight -30
}
vrrp_instance VI-kube-master {
    state MASTER
    priority 120
    dont_track_primary
    interface eth0         #根据具体情况修改网卡名!
    virtual_router_id 68
    advert_int 3
    track_script {
        check-haproxy
    }
    virtual_ipaddress {
        192.168.1.101   #设置虚拟IP,可以设置多个 。(要参考内网的环境与此IP通信问题)
    }
}

注:
我的VIP 所在的接口nterface 为 eth1;根据自己的情况改变
使用 killall -0 haproxy 命令检查所在节点的 haproxy 进程是否正常。如果异常则将权重减少(-30),从而触发重新选主过程;
router_id、virtual_router_id 用于标识属于该 HA 的 keepalived 实例,如果有多套keepalived HA,则必须各不相同;

(2)在两台backup 上配置文件:(根据需要修改虚拟IP)

[root@node01 ~]# vim /etc/keepalived/keepalived.conf

global_defs {
        router_id keepalived_hap
}
vrrp_script check-haproxy {
        script "killall -0 haproxy"
        interval 5
        weight -30
}
vrrp_instance VI-kube-master {
        state BACKUP
        priority 110            #第2台从为100
        dont_track_primary
        interface eth0
        virtual_router_id 68
        advert_int 3
        track_script {
        check-haproxy
        }
#        authentication {                          #设置登录账户和密码!
#                auth_type admin
#                auth_pass admin-2019
        }
        virtual_ipaddress {
                192.168.1.101   #设置虚拟IP,可以设置多个 。(要参考内网的环境与此IP通信问题)
        }
}

注:
我的VIP 所在的接口nterface 为 eth1;根据自己的情况改变
使用 killall -0 haproxy 命令检查所在节点的 haproxy 进程是否正常。如果异常则将权重减少(-30),从而触发重新选主过程;
router_id、virtual_router_id 用于标识属于该 HA 的 keepalived 实例,如果有多套keepalived HA,则必须各不相同;
priority 的值必须小于 master 的值;两个从的值也需要不一样;

(3)开启keepalived 服务

[root@kube-master01 ~]# vim /opt/k8s/script/keepalived.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
VIP="192.168.1.101"
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl restart keepalived && systemctl enable keepalived"
    ssh root@${node_ip} "systemctl status keepalived|grep Active"
    ssh ${node_ip} "ping -c 1 ${VIP}"
done
[root@kube-master01 ~]# chmod +x /opt/k8s/script/keepalived.sh && /opt/k8s/script/keepalived.sh

(4)在master服务器上能看到eth0网卡上已经有192.168.1.101 VIP了

查看 haproxy 状态页面

浏览器访问 192.168.1.101:10080/status 地址(帐号密码在haproxy配置文件!)

7.2、部署 kube-apiserver 组件

下载二进制文件
创建 kubernetes 证书和私钥

(1)创建证书签名请求:

[root@kube-master01 cert]# cd /opt/k8s/cert/
[root@kube-master01 cert]# cat > kubernetes-csr.json <<EOF

{
    "CN": "kubernetes",
    "hosts": [
        "127.0.0.1",
        "192.168.1.201",
        "192.168.1.202",
        "192.168.1.203",
        "192.168.1.101",
        "10.30.0.1",
        "kubernetes",
        "kubernetes.default",
        "kubernetes.default.svc",
        "kubernetes.default.svc.cluster",
        "kubernetes.default.svc.cluster.local"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
          "C": "CN",
          "ST": "BeiJing",
          "L": "BeiJing",
          "O": "k8s",
          "OU": "4Paradigm"
        }
    ]
}

注:
hosts 字段指定授权使用该证书的 IP 或域名列表,这里列出了 VIP 、apiserver节点 IP、kubernetes 服务 IP 和域名;
域名最后字符不能是 . (如不能为kubernetes.default.svc.cluster.local. ),否则解析时失败,提示: x509:cannot parse dnsName "kubernetes.default.svc.cluster.local." ;
如果使用非 cluster.local 域名,如 opsnull.com ,则需要修改域名列表中的最后两个域名为: kubernetes.default.svc.opsnull 、 kubernetes.default.svc.opsnull.com
kubernetes 服务 IP 是 apiserver 自动创建的,一般是 --service-cluster-ip-range 参数指定的网段的第一个IP,后续可以通过如下命令获取:

(2)生成证书和私钥

[root@kube-master01 cert]# cfssl_linux-amd64 gencert -ca=/opt/k8s/cert/ca.pem -ca-key=/opt/k8s/cert/ca-key.pem -config=/opt/k8s/cert/ca-config.json -profile=kubernetes kubernetes-csr.json | cfssljson_linux-amd64 -bare kubernetes

检查:

[root@kube-master01 cert]# ll kubernetes*
-rw-r--r-- 1 root root 1273 8月  14 13:57 kubernetes.csr
-rw-r--r-- 1 root root  597 8月  14 13:57 kubernetes-csr.json
-rw------- 1 root root 1675 8月  14 13:57 kubernetes-key.pem
-rw-r--r-- 1 root root 1643 8月  14 13:57 kubernetes.pem
创建加密配置文件

① 产生一个用来加密Etcd 的 Key:

[root@kube-master01 cert]# head -c 32 /dev/urandom | base64
dgHHJ1tcMXFFu/ka/qaTmVKPuKueFwjYhSF9JOLoU0g=

注意:每台master节点需要用一样的 Key

② 使用这个加密的key,创建加密配置文件

[root@kube-master01 ~]# vim /opt/k8s/cert/encryption-config.yaml

kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret:MKt3DHKkAgfrzm/adqxV5VEMnobjKcol2KggacS56yY=
      - identity: {}
将生成的证书和私钥文件、加密配置文件拷贝到各个master 节点的/opt/k8s目录下
[root@kube-master01 ~]# vim /opt/k8s/script/scp_apiserver.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
    echo  ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p /opt/k8s/cert/ && sudo chown -R k8s /opt/k8s/cert/"
    scp /opt/k8s/cert/kubernetes*.pem k8s@${node_ip}:/opt/k8s/cert/
    scp /opt/k8s/cert/encryption-config.yaml root@${node_ip}:/opt/k8s/
done 

执行:

[root@kube-master01 ~]# chmod +x /opt/k8s/script/scp_apiserver.sh && /opt/k8s/script/scp_apiserver.sh
创建 kube-apiserver systemd unit 模板文件
[root@kube-master01 ~]# mkdir -p /opt/apiserver/

[root@kube-master01 ~]# cat > /opt/apiserver/kube-apiserver.service.template <<EOF

[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
ExecStart=/opt/k8s/bin/kube-apiserver \
--enable-admission-plugins=Initializers,NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
--anonymous-auth=false \
--experimental-encryption-provider-config=/opt/k8s/encryption-config.yaml \
--advertise-address=##NODE_IP## \         
--bind-address=##NODE_IP## \
--insecure-port=0 \
--authorization-mode=Node,RBAC \
--runtime-config=api/all \
--enable-bootstrap-token-auth \
--service-cluster-ip-range=10.30.0.0/16 \      
--service-node-port-range=30000-32767 \
--tls-cert-file=/opt/k8s/cert/kubernetes.pem \
--tls-private-key-file=/opt/k8s/cert/kubernetes-key.pem \
--client-ca-file=/opt/k8s/cert/ca.pem \
--kubelet-client-certificate=/opt/k8s/cert/kubernetes.pem \
--kubelet-client-key=/opt/k8s/cert/kubernetes-key.pem \
--service-account-key-file=/opt/k8s/cert/ca-key.pem \
--etcd-cafile=/opt/k8s/cert/ca.pem \
--etcd-certfile=/opt/k8s/cert/kubernetes.pem \
--etcd-keyfile=/opt/k8s/cert/kubernetes-key.pem \
--etcd-servers=https://192.168.1.201:2379,https://192.168.1.202:2379,https://192.168.1.203:2379 \
--enable-swagger-ui=true \
--allow-privileged=true \
--apiserver-count=3 \
--audit-log-maxage=30 \
--audit-log-maxbackup=3 \
--audit-log-maxsize=100 \
--audit-log-path=/var/log/kube-apiserver-audit.log \
--event-ttl=1h \
--alsologtostderr=true \
--logtostderr=false \
--log-dir=/opt/log/kubernetes \
--v=2
Restart=on-failure
RestartSec=5
Type=notify
User=k8s
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

注:
--experimental-encryption-provider-config :启用加密特性;
--authorization-mode=Node,RBAC : 开启 Node 和 RBAC 授权模式,拒绝未授权的请求;
--enable-admission-plugins :启用 ServiceAccount 和NodeRestriction ;
--service-account-key-file :签名 ServiceAccount Token 的公钥文件,kube-controller-manager 的 --service-account-private-key-file 指定私钥文件,两者配对使用;
--tls--file :指定 apiserver 使用的证书、私钥和 CA 文件。 --client-ca-file 用于验证 client (kue-controller-manager、kube-scheduler、kubelet、kube-proxy 等)请求所带的证书;
--kubelet-client-certificate 、 --kubelet-client-key :如果指定,则使用 https 访问 kubelet APIs;需要为证书对应的用户(上面 kubernetes
.pem 证书的用户为 kubernetes) 用户定义 RBAC 规则,否则访问 kubelet API 时提示未授权;
--bind-address : 不能为 127.0.0.1 ,否则外界不能访问它的安全端口6443;
--insecure-port=0 :关闭监听非安全端口(8080);
--service-cluster-ip-range : 指定 Service Cluster IP 地址段;
--service-node-port-range : 指定 NodePort 的端口范围!!!;
--runtime-config=api/all=true : 启用所有版本的 APIs,如autoscaling/v2alpha1;
--enable-bootstrap-token-auth :启用 kubelet bootstrap 的 token 认证;
--apiserver-count=3 :指定集群运行模式,多台 kube-apiserver 会通过 leader选举产生一个工作节点,其它节点处于阻塞状态;
User=k8s :使用 k8s 账户运行;

为各节点创建和分发 kube-apiserver systemd unit文件;启动检查 kube-apiserver 服务
[root@kube-master01 ~]# vim /opt/k8s/script/apiserver_service.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
#替换模板文件中的变量,为各节点创建 systemd unit 文件
for (( i=0; i < 3; i++ ));do
    sed "s/##NODE_IP##/${NODE_IPS[i]}/" /opt/apiserver/kube-apiserver.service.template > /opt/apiserver/kube-apiserver-${NODE_IPS[i]}.service
done
#启动并检查 kube-apiserver 服务
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p /opt/log/kubernetes && chown -R k8s /opt/log/kubernetes"
    scp /opt/apiserver/kube-apiserver-${node_ip}.service root@${node_ip}:/etc/systemd/system/kube-apiserver.service
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kube-apiserver && systemctl restart kube-apiserver"
    ssh root@${node_ip} "systemctl status kube-apiserver |grep 'Active:'"
done

执行:

[root@kube-master01 ~]# chmod +x /opt/k8s/script/apiserver_service.sh && /opt/k8s/script/apiserver_service.sh

7.3 部署高可用kube-controller-manager 集群

该集群包含 3 个节点,启动后将通过竞争选举机制产生一个 leader 节点,其它节点为阻塞状态。
当 leader 节点不可用后,剩余节点将再次进行选举产生新的 leader 节点,从而保证服务的可用性。

为保证通信安全,本文档先生成 x509 证书和私钥,kube-controller-manager 在如下两种情况下使用该证书:
① 与 kube-apiserver 的安全端口通信时;
② 在安全端口(https,10252) 输出 prometheus 格式的 metrics;

准备工作:下载最新版本的二进制文件、安装和配置 flanneld
创建 kube-controller-manager 证书和私钥
[root@kube-master01 ~]# cd /opt/k8s/cert/

[root@kube-master01 cert ]# vi /opt/k8s/cert/kube-controller-manager-csr.json
{
    "CN": "system:kube-controller-manager",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "hosts": [
        "127.0.0.1",
        "192.168.1.201",
        "192.168.1.202",
        "192.168.1.203"
    ],
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "system:kube-controller-manager",
            "OU": "4Paradigm"
        }
    ]
}

注:
hosts 列表包含所有 kube-controller-manager 节点 IP;
CN 为 system:kube-controller-manager、O 为 system:kube-controller-manager,kubernetes 内置的 ClusterRoleBindings system:kube-controller-manager 赋予kube-controller-manager 工作所需的权限。

生成证书和私钥
[root@kube-master01 cert]# cfssl_linux-amd64 gencert -ca=/opt/k8s/cert/ca.pem -ca-key=/opt/k8s/cert/ca-key.pem -config=/opt/k8s/cert/ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson_linux-amd64 -bare kube-controller-manager

查看&验证

[root@kube-master01 cert]# ll *controller-manager*
-rw-r--r-- 1 root root 1139 8月  29 17:44 kube-controller-manager.csr
-rw-r--r-- 1 root root  431 8月  29 17:29 kube-controller-manager-csr.json
-rw------- 1 root root 1679 8月  29 17:44 kube-controller-manager-key.pem
-rw-r--r-- 1 root root 1517 8月  29 17:44 kube-controller-manager.pe
创建kubeconfig 文件

kubeconfig 文件包含访问 apiserver 的所有信息,如 apiserver 地址、CA 证书和自身使用的证书;

① 执行命令,生产kube-controller-manager.kubeconfig文件

[root@kube-master01 ~]# kubectl config set-cluster kubernetes --certificate-authority=/opt/k8s/cert/ca.pem --embed-certs=true --server=https://192.168.1.101:8443 --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

[root@kube-master01 ~]# kubectl config set-credentials system:kube-controller-manager --client-certificate=/opt/k8s/cert/kube-controller-manager.pem --client-key=/opt/k8s/cert/kube-controller-manager-key.pem --embed-certs=true --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

[root@kube-master01 ~]# kubectl config set-context system:kube-controller-manager@kubernetes --cluster=kubernetes --user=system:kube-controller-manager --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

[root@kube-master01 ~]# kubectl config use-context system:kube-controller-manager@kubernetes --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

② 验证kube-controller-manager.kubeconfig文件

[root@kube-master01 ~]# ll /root/.kube/kube-controller-manager.kubeconfig

-rw------- 1 root root 6545 8月  29 17:51 /root/.kube/kube-controller-manager.kubeconfig
[root@kube-master01 ~]# kubectl config view --kubeconfig=/root/.kube/kube-controller-manager.kubeconfig

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://192.168.1.101:8443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: system:kube-controller-manager
  name: system:kube-controller-manager@kubernetes
current-context: system:kube-controller-manager@kubernetes
kind: Config
preferences: {}
users:
- name: system:kube-controller-manager
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
分发生成的证书和私钥、kubeconfig 到所有 master 节点
[root@kube-master01 ~]# vim /opt/k8s/script/scp_controller_manager.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "chown k8s /opt/k8s/cert/*"
    scp /opt/k8s/cert/kube-controller-manager*.pem k8s@${node_ip}:/opt/k8s/cert/
    scp /root/.kube/kube-controller-manager.kubeconfig k8s@${node_ip}:/opt/k8s/
done

[root@kube-master01 ~]#  chmod +x /opt/k8s/script/scp_controller_manager.sh && /opt/k8s/script/scp_controller_manager.sh
创建和分发 kube-controller-manager systemd unit 文件
[root@kube-master01 ~]# mkdir /opt/controller_manager
[root@kube-master01 ~]# cd /opt/controller_manager

[root@kube-master01 controller_manager]# vi kube-controller-manager.service

[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/opt/k8s/bin/kube-controller-manager \
--port=0 \
--secure-port=10252 \
--bind-address=127.0.0.1 \
--kubeconfig=/opt/k8s/kube-controller-manager.kubeconfig \
--service-cluster-ip-range=10.30.0.0/16 \
--cluster-name=kubernetes \
--cluster-signing-cert-file=/opt/k8s/cert/ca.pem \
--cluster-signing-key-file=/opt/k8s/cert/ca-key.pem \
--experimental-cluster-signing-duration=8760h \
--root-ca-file=/opt/k8s/cert/ca.pem \
--service-account-private-key-file=/opt/k8s/cert/ca-key.pem \
--leader-elect=true \
--feature-gates=RotateKubeletServerCertificate=true \
--controllers=*,bootstrapsigner,tokencleaner \
--horizontal-pod-autoscaler-use-rest-clients=true \
--horizontal-pod-autoscaler-sync-period=10s \
--tls-cert-file=/opt/k8s/cert/kube-controller-manager.pem \
--tls-private-key-file=/opt/k8s/cert/kube-controller-manager-key.pem \
--use-service-account-credentials=true \
--alsologtostderr=true \
--logtostderr=false \
--log-dir=/var/log/kubernetes \
--v=2
Restart=on
Restart=on-failure
RestartSec=5
User=k8s

[Install]
WantedBy=multi-user.target

注:
--port=0:关闭监听 http /metrics 的请求,同时 --address 参数无效,--bind-address 参数有效;
--secure-port=10252、--bind-address=0.0.0.0: 在所有网络接口监听 10252 端口的 https /metrics 请求;
--kubeconfig:指定 kubeconfig 文件路径,kube-controller-manager 使用它连接和验证 kube-apiserver;
--cluster-signing--file:签名 TLS Bootstrap 创建的证书;
--experimental-cluster-signing-duration:指定 TLS Bootstrap 证书的有效期;
--root-ca-file:放置到容器 ServiceAccount 中的 CA 证书,用来对 kube-apiserver 的证书进行校验;
--service-account-private-key-file:签名 ServiceAccount 中 Token 的私钥文件,必须和 kube-apiserver 的 --service-account-key-file 指定的公钥文件配对使用;
--service-cluster-ip-range :指定 Service Cluster IP 网段,必须和 kube-apiserver 中的同名参数一致;
--leader-elect=true:集群运行模式,启用选举功能;被选为 leader 的节点负责处理工作,其它节点为阻塞状态;
--feature-gates=RotateKubeletServerCertificate=true:开启 kublet server 证书的自动更新特性;
--controllers=
,bootstrapsigner,tokencleaner:启用的控制器列表,tokencleaner 用于自动清理过期的 Bootstrap token;
--horizontal-pod-autoscaler-*:custom metrics 相关参数,支持 autoscaling/v2alpha1;
--tls-cert-file、--tls-private-key-file:使用 https 输出 metrics 时使用的 Server 证书和秘钥;
--use-service-account-credentials=true:
User=k8s:使用 k8s 账户运行;
kube-controller-manager 不对请求 https metrics 的 Client 证书进行校验,故不需要指定 --tls-ca-file 参数,而且该参数已被淘汰。
------------------
kube-controller-manager 的权限
ClusteRole: system:kube-controller-manager 的权限很小,只能创建 secret、serviceaccount 等资源对象,各 controller 的权限分散到 ClusterRole system:controller:XXX 中。

  需要在 kube-controller-manager 的启动参数中添加 --use-service-account-credentials=true 参数,这样 main controller 会为各 controller 创建对应的 ServiceAccount XXX-controller。

  内置的 ClusterRoleBinding system:controller:XXX 将赋予各 XXX-controller ServiceAccount 对应的 ClusterRole system:controller:XXX 权限。

分发systemd unit 文件到所有master 节点;启动检查 kube-controller-manager 服务
[root@kube-master01 ~]# vim /opt/k8s/script/controller_manager.sh

NODE_IPS=("192.168.1.201" "192.168.1.202" "192.168.1.203")
for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        scp /opt/controller_manager/kube-controller-manager.service root@${node_ip}:/etc/systemd/system/
        ssh root@${node_ip} "mkdir -p /opt/log/kubernetes && chown -R k8s /opt/log/kubernetes"
        ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kube-controller-manager && systemctl start kube-controller-manager"
done

for node_ip in ${NODE_IPS[@]};do
        echo ">>> ${node_ip}"
        ssh k8s@${node_ip} "systemctl status kube-controller-manager|grep Active"
done
[root@kube-master ~]# chmod +x /opt/k8s/script/controller_manager.sh && /opt/k8s/script/controller_manager.sh
查看输出的 metric

转载于:https://www.cnblogs.com/colman/p/11310594.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值