k8s1.8 TLS二进制离线部署

kubernetes 集群部署(TLS认证)

第1章 部署准备
1.1 组件版本 && 集群环境
1.1.1 组件版本

Kubernetes 1.8.3
Docker 18.03.1-ce
Etcd 3.2.9
Flanneld
TLS 认证通信(所有组件,如etcd、kubernetes master 和node)
RBAC 授权
kubelet TLS Bootstrapping

1.1.2 集群环境

[root@k8s_master ~]# uname -a
Linux k8s_master 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
[root@k8s_master ~]# cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core)
两台服务器(一台用作master一台用作slave)
10.0.0.190   k8s_master
10.0.0.191   k8s_slave

1.2 集群环境变量

# TLS Bootstrapping 使用的Token,可以使用命令 head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成
BOOTSTRAP_TOKEN="8981b594122ebed7596f1d3b69c78223"

# 建议使用未用的网段来定义服务网段和Pod 网段
# 服务网段(Service CIDR),部署前路由不可达,部署后集群内部使用IP:Port可达
SERVICE_CIDR="10.254.0.0/16"
# Pod 网段(Cluster CIDR),部署前路由不可达,部署后路由可达(flanneld 保证)
CLUSTER_CIDR="172.30.0.0/16"

# 服务端口范围(NodePort Range)
NODE_PORT_RANGE="30000-32766"            #创建pod后分配端口范围

# etcd服务地址列表
ETCD_ENDPOINTS="http://10.0.0.190:2379"   #etcd服务地址

# flanneld 网络配置前缀
FLANNEL_ETCD_PREFIX="/k8s/network"

# kubernetes 服务IP(预先分配,一般为SERVICE_CIDR中的第一个IP)
CLUSTER_KUBERNETES_SVC_IP="10.254.0.1"

# 集群 DNS 服务IP(从SERVICE_CIDR 中预先分配)
CLUSTER_DNS_SVC_IP="10.254.0.2"

# 集群 DNS 域名
CLUSTER_DNS_DOMAIN="cluster.local."

说明:将上面变量保存为: env.sh,然后将脚本拷贝到所有机器的/usr/local/bin目录。
第2章 创建CA 证书和密钥
kubernetes 系统各个组件需要使用TLS证书对通信进行加密,这里我们使用CloudFlare的PKI 工具集cfssl 来生成Certificate Authority(CA) 证书和密钥文件, CA 是自签名的证书,用来签名后续创建的其他TLS 证书。
2.1 安装 CFSSL

[root@k8s_master ~]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
[root@k8s_master ~]# chmod +x cfssl_linux-amd64
[root@k8s_master ~]# mv cfssl_linux-amd64 /usr/bin/cfssl

[root@k8s_master ~]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
[root@k8s_master ~]# chmod +x cfssljson_linux-amd64
[root@k8s_master ~]# mv cfssljson_linux-amd64 /usr/bin/cfssljson

[root@k8s_master ~]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
[root@k8s_master ~]# chmod +x cfssl-certinfo_linux-amd64
[root@k8s_master ~]# mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo

[root@k8s_master ~]# export PATH=/usr/k8s/bin:$PATH
[root@k8s_master ~]# mkdir ssl && cd ssl
[root@k8s_master ssl]# cfssl print-defaults config > config.json
[root@k8s_master ssl]# cfssl print-defaults csr > csr.json

说明:为了方便,将/usr/local/bin设置成环境变量,为了重启也有效,可以将上面的export PATH=/usr/local/bin:$PATH添加到/etc/rc.local文件中。
2.2 创建CA
2.2.1 修改上面创建的config.json文件为ca-config.json:

[root@k8s_master ssl]# cat ca-config.json
{
    "signing": {
        "default": {
            "expiry": "8760h"         #证书的有效时间
        },
        "profiles": {
            "kubernetes": {
                "expiry": "8760h",        #证书的有效时间
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth",
                    "client auth"
                ]
            }
        }
    }
}

参数说明:
config.json:可以定义多个profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个profile;
signing: 表示该证书可用于签名其它证书;生成的ca.pem 证书中CA=TRUE;
server auth: 表示client 可以用该CA 对server 提供的证书进行校验;
client auth: 表示server 可以用该CA 对client 提供的证书进行验证。

2.2.2 修改CA 证书签名为ca-csr.json:

[root@k8s_master ssl]# cat ca-csr.json
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}


参数说明:
CN: Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名(User Name);浏览器使用该字段验证网站是否合法;
O: Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组(Group);

2.2.2.1 生成CA 证书和私钥:

[root@k8s_master ssl]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2018/09/15 09:08:00 [INFO] generating a new CA key and certificate from CSR
2018/09/15 09:08:00 [INFO] generate received request
2018/09/15 09:08:00 [INFO] received CSR
2018/09/15 09:08:00 [INFO] generating key: rsa-2048
2018/09/15 09:08:00 [INFO] encoded CSR
2018/09/15 09:08:00 [INFO] signed certificate with serial number 388728220321633548679905650114339188496612614157
[root@k8s_master ssl]# ls ca*
ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem

2.2.3 分发证书
2.2.3.1 将生成的CA 证书、密钥文件、配置文件拷贝到所有机器的/etc/kubernetes/ssl目录下面:

[root@k8s_master ssl]# mkdir -p /etc/kubernetes/ssl
[root@k8s_master ssl]# cp ca* /etc/kubernetes/ssl

第3章 k8s集群部署
3.1 部署etcd服务
3.1.1 定义环境变量

export NODE_NAME=k8s_master  # 当前部署的机器名称(随便定义,只要能区分不同机器即可)
export NODE_IP=10.0.0.190    # 当前部署的机器IP
export NODE_IPS="10.0.0.190" # etcd服务的 IP
# etcd的IP和端口
export ETCD_NODES=k8s_master=http://10.0.0.190
# 导入用到的其它全局变量:ETCD_ENDPOINTS、FLANNEL_ETCD_PREFIX、CLUSTER_CIDR
source /usr/local/bin/env.sh

3.1.2 下载etcd 二进制文件
3.1.2.1 到https://github.com/coreos/etcd/releases页面下载最新版本的二进制文件:

[root@k8s_master ~]# wget https://github.com/coreos/etcd/releases/download/v3.2.9/etcd-v3.2.9-linux-amd64.tar.gz
[root@k8s_master ~]# tar xf etcd-v3.2.9-linux-amd64.tar.gz
[root@k8s_master ~]# cp etcd-v3.2.9-linux-amd64/etcd* /usr/bin/
[root@k8s_master ~]# ll /usr/bin/etcd*
-rwxrwxr-x 1 1000 1000 17123360 Oct  6  2017 /usr/bin/etcd
-rwxrwxr-x 1 1000 1000 14640128 Oct  6  2017 /usr/bin/etcdctl

3.1.3 创建etcd 的systemd unit 文件

[root@k8s_master ~]# mkdir -p /var/lib/etcd    # 必须要先创建工作目录
[root@k8s_master ~]# cat > etcd.service <<EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
ExecStart=/usr/bin/etcd \\
  --name=k8s_master \\
  --initial-advertise-peer-urls=http://10.0.0.190:2380 \\
  --listen-peer-urls=http://10.0.0.190:2380 \\
  --listen-client-urls=http://10.0.0.190:2379,http://127.0.0.1:2379 \\
  --advertise-client-urls=http://10.0.0.190:2379 \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

指定etcd的工作目录和数据目录为/var/lib/etcd,需要在启动服务前创建这个目录
3.1.3.1 启动etcd 服务

[root@k8s_master ~]# mv etcd.service /usr/lib/systemd/system/
[root@k8s_master ~]# systemctl start etcd
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl start etcd
[root@k8s_master ~]# systemctl status etcd
[root@k8s_master ~]# systemctl enable etcd

3.2 配置kubectl 命令行工具
说明:kubectl默认从~/.kube/config配置文件中获取访问kube-apiserver 地址、证书、用户名等信息,需要正确配置该文件才能正常使用kubectl命令。
需要将下载的kubectl 二进制文件和生产的~/.kube/config配置文件拷贝到需要使用kubectl 命令的机器上。
3.2.1 环境变量

[root@k8s_master ~]# source /usr/local/bin/env.sh
[root@k8s_master ~]# export KUBE_APISERVER="https://10.0.0.190:6443"
[root@k8s_master ~]# echo $KUBE_APISERVER
https://10.0.0.190:6443

变量KUBE_APISERVER 指定kubelet 访问的kube-apiserver 的地址,后续被写入~/.kube/config配置文件
3.2.2 下载并复制二进制文件到/usr/bin目录

https://github.com/kubernetes/kubernetes/releases    (k8s各版本下载)
[root@k8s_master ~]# wget https://dl.k8s.io/v1.8.3/kubernetes-server-linux-amd64.tar.gz
[root@k8s_master ~]# tar xf kubernetes-server-linux-amd64.tar.gz
[root@k8s_master ~]# cp kubernetes/server/bin/{kubectl,kubefed} /usr/bin/
[root@k8s_master ~]# ll /usr/bin/kube*
-rwxr-x--- 1 root root 52269537 Sep 15 10:10 /usr/bin/kubectl
-rwxr-x--- 1 root root 55868971 Sep 15 10:10 /usr/bin/kubefed
[root@k8s_master ~]# export PATH=/usr/local/bin:$PATH

3.2.3 创建admin 证书
3.2.3.1 kubectl 与kube-apiserver 的安全端口通信,需要为安全通信提供TLS 证书和密钥。创建admin 证书:

[root@k8s_master ~]# cd ssl/
cat > admin-csr.json <<EOF
{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}
EOF

说明:
1)后续kube-apiserver使用RBAC 对客户端(如kubelet、kube-proxy、Pod)请求进行授权
2)kube-apiserver 预定义了一些RBAC 使用的RoleBindings,如cluster-admin 将Group system:masters与Role cluster-admin绑定,该Role 授予了调用kube-apiserver所有API 的权限
3)O 指定了该证书的Group 为system:masters,kubectl使用该证书访问kube-apiserver时,由于证书被CA 签名,所以认证通过,同时由于证书用户组为经过预授权的system:masters,所以被授予访问所有API 的劝降
4)hosts 属性值为空列表
3.2.4 生成admin 证书和私钥:

[root@k8s_master ssl]# cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \
  -ca-key=/etc/kubernetes/ssl/ca-key.pem \
  -config=/etc/kubernetes/ssl/ca-config.json \
  -profile=kubernetes admin-csr.json | cfssljson -bare admin
[root@k8s_master ssl]# ls admin*
admin.csr  admin-csr.json  admin-key.pem  admin.pem
[root@k8s_master ssl]# mv admin*.pem /etc/kubernetes/ssl/

3.2.5 创建kubectl kubeconfig 文件

# 设置集群参数
[root@k8s_master ssl]# kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER}
# 设置客户端认证参数
[root@k8s_master ssl]# kubectl config set-credentials admin \
  --client-certificate=/etc/kubernetes/ssl/admin.pem \
  --embed-certs=true \
  --client-key=/etc/kubernetes/ssl/admin-key.pem 
# 设置上下文参数
[root@k8s_master ssl]# kubectl config set-context kubernetes \
  --cluster=kubernetes \
  --user=admin
# 设置默认上下文
[root@k8s_master ssl]# kubectl config use-context kubernetes
  1. admin.pem证书O 字段值为system:masters,kube-apiserver 预定义的 RoleBinding cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予了调用kube-apiserver 相关 API 的权限
  2. 生成的kubeconfig 被保存到 ~/.kube/config 文件
    3.2.5.1 分发kubeconfig 文件
    /.kube/config文件拷贝到运行kubectl命令的机器的/.kube/目录下去。

3.3 部署Flannel 网络
kubernetes 要求集群内各节点能通过Pod 网段互联互通,下面我们来使用Flannel 在所有节点上创建互联互通的Pod 网段的步骤。
3.3.1 环境变量

[root@k8s_master ssl]# export NODE_IP=10.0.0.190  #当前部署节点的ip
[root@k8s_master ssl]# source /usr/local/bin/env.sh    #导入全局环境变量

3.3.2 向etcd 写入集群Pod 网段信息

[root@k8s_master ssl]# etcdctl set /k8s/network/config '{"Network":"'172.30.0.0/16'"}'
{"Network":"172.30.0.0/16"}
[root@k8s-master ~]# etcdctl get /k8s/network/config
{ "Network": "172.30.0.0/16" }

写入的 Pod 网段(172.30.0.0/16) 必须与kube-controller-manager 的 --cluster-cidr 选项值一致;
3.3.3 安装和配置flanneld
3.3.3.1 前往flanneld release页面下载最新版的flanneld 二进制文件:

[root@k8s_master ~]# mkdir flannel
[root@k8s_master ~]# wget https://github.com/coreos/flannel/releases/download/v0.9.0/flannel-v0.9.0-linux-amd64.tar.gz
[root@k8s_master ~]# tar -xzvf flannel-v0.9.0-linux-amd64.tar.gz -C flannel
[root@k8s_master ~]# cp flannel/{flanneld,mk-docker-opts.sh} /usr/bin

3.3.3.2 创建flanneld的systemd unit 文件

[root@k8s_master ~]# cat > 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=/usr/bin/flanneld \\
  -etcd-endpoints=${ETCD_ENDPOINTS} \\
  -etcd-prefix=${FLANNEL_ETCD_PREFIX}
ExecStartPost=/usrl/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=on-failure

[Install]
WantedBy=multi-user.target
RequiredBy=docker.service
EOF
1)	mk-docker-opts.sh脚本将分配给flanneld 的Pod 子网网段信息写入到/run/flannel/docker 文件中,后续docker 启动时使用这个文件中的参数值为 docker0 网桥
2)	flanneld 使用系统缺省路由所在的接口和其他节点通信,对于有多个网络接口的机器(内网和公网),可以用 --iface 选项值指定通信接口(上面的 systemd unit 文件没指定这个选项)

3.3.3.4 启动flanneld

[root@k8s_master ~]# mv flanneld.service /usr/lib/systemd/system/
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl start flannel
[root@k8s_master ~]# systemctl status flanneld
[root@k8s_master ~]# systemctl enable flanneld

3.4 部署master 节点
3.4.1 kubernetes master 节点包含的组件有:

1.	kube-apiserver
2.	kube-scheduler
3.	kube-controller-manager

说明:目前这3个组件需要部署到同一台机器上:

  1. kube-scheduler、kube-controller-manager 和 kube-apiserver 三者的功能紧密相关;
  2. 同时只能有一个 kube-scheduler、kube-controller-manager 进程处于工作状态,如果运行多个,则需要通过选举产生一个 leader;
  3. master 节点与node 节点上的Pods 通过Pod 网络通信,所以需要在master 节点上部署Flannel 网络。
    3.4.2 环境变量
[root@k8s_master ~]# export MASTER_IP=10.0.0.190  #当前部署master节点ip
[root@k8s_master ~]# source /usr/local/bin/env.sh

3.4.3 下载最新版本的二进制文件

https://github.com/kubernetes/kubernetes/releases     #k8s版本下载连接
[root@k8s_master ~]#  wget https://dl.k8s.io/v1.8.3/kubernetes-server-linux-amd64.tar.gz
[root@k8s_master ~]#  tar -xzvf kubernetes-server-linux-amd64.tar.gz
[root@k8s_master ~]#  cd kubernetes

3.4.3.1 将二进制文件拷贝到/usr/bin目录

[root@k8s_master ~]# cp -r server/bin/{kube-apiserver,kube-controller-manager,kube-scheduler,kube-proxy,kubelet} /usr/bin/

3.4.4 创建kubernetes 证书
3.4.4.1 创建kubernetes 证书签名请求:

[root@k8s_master ~]# cat > kubernetes-csr.json <<EOF
{
  "CN": "kubernetes",
  "hosts": [
    "127.0.0.1",
    "${MASTER_IP}",
    "${CLUSTER_KUBERNETES_SVC_IP}",
    "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": "System"
    }
  ]
}
EOF

 如果 hosts 字段不为空则需要指定授权使用该证书的 IP 或域名列表,所以上面分别指定了当前部署的 master 节点主机 IP 以及apiserver 负载的内部域名
 还需要添加 kube-apiserver 注册的名为 kubernetes 的服务 IP (Service Cluster IP),一般是 kube-apiserver --service-cluster-ip-range 选项值指定的网段的第一个IP,如 “10.254.0.1”
3.4.4.2 生成kubernetes 证书和私钥:

[root@k8s_master ssl]# cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \
  -ca-key=/etc/kubernetes/ssl/ca-key.pem \
  -config=/etc/kubernetes/ssl/ca-config.json \
  -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
[root@k8s_master ssl]# ls kubernetes*
kubernetes.csr  kubernetes-csr.json  kubernetes-key.pem  kubernetes.pem
[root@k8s_master ssl]# mv kubernetes*.pem /etc/kubernetes/ssl/

3.4.5 配置和启动kube-apiserver
3.4.5.1 创建kube-apiserver 使用的客户端token 文件
kubelet 首次启动时向kube-apiserver 发送TLS Bootstrapping 请求,kube-apiserver 验证请求中的token 是否与它配置的token.csv 一致,如果一致则自动为kubelet 生成证书和密钥。

#导入的env.sh文件定义了BOOTSTRAP_TOKEN变量
[root@k8s_master ssl]# cat > token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
[root@k8s_master ssl]# mv token.csv /etc/kubernetes/

3.4.5.2 创建kube-apiserver 的systemd unit文件

cat  > kube-apiserver.service <<EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
ExecStart=/usr/bin/kube-apiserver \\
  --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
  --advertise-address=${MASTER_IP} \\
  --bind-address=${MASTER_IP} \\
  --insecure-bind-address=${MASTER_IP} \\
  --authorization-mode=Node,RBAC \\
  --runtime-config=rbac.authorization.k8s.io/v1alpha1 \\
  --kubelet-https=true \\
  --experimental-bootstrap-token-auth \\
  --token-auth-file=/etc/kubernetes/token.csv \\
  --service-cluster-ip-range=${SERVICE_CIDR} \\
  --service-node-port-range=${NODE_PORT_RANGE} \\
  --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem \\
  --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \\
  --client-ca-file=/etc/kubernetes/ssl/ca.pem \\
  --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \\
  --etcd-cafile=/etc/kubernetes/ssl/ca.pem \\
  --etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem \\
  --etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem \\
  --etcd-servers=${ETCD_ENDPOINTS} \\
  --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/lib/audit.log \\
  --event-ttl=1h \\
  --v=2
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

 kube-apiserver 1.6 版本开始使用 etcd v3 API 和存储格式
 --authorization-mode=RBAC 指定在安全端口使用RBAC 授权模式,拒绝未通过授权的请求
 kube-scheduler、kube-controller-manager 一般和 kube-apiserver 部署在同一台机器上,它们使用非安全端口和 kube-apiserver通信
 kubelet、kube-proxy、kubectl 部署在其它 Node 节点上,如果通过安全端口访问 kube-apiserver,则必须先通过 TLS 证书认证,再通过 RBAC 授权
 kube-proxy、kubectl 通过使用证书里指定相关的 User、Group 来达到通过 RBAC 授权的目的
 如果使用了 kubelet TLS Boostrap 机制,则不能再指定 --kubelet-certificate-authority、–kubelet-client-certificate 和 --kubelet-client-key 选项,否则后续 kube-apiserver 校验 kubelet 证书时出现 ”x509: certificate signed by unknown authority“ 错误
 --admission-control 值必须包含 ServiceAccount,否则部署集群插件时会失败
 --bind-address 不能为 127.0.0.1
 --service-cluster-ip-range 指定 Service Cluster IP 地址段,该地址段不能路由可达
 --service-node-port-range=${NODE_PORT_RANGE} 指定 NodePort 的端口范围
 缺省情况下 kubernetes 对象保存在etcd/registry 路径下,可以通过 --etcd-prefix 参数进行调整
 kube-apiserver 1.8版本后需要在–authorization-mode参数中添加Node,即:–authorization-mode=Node,RBAC,否则Node 节点无法注册
3.4.5.3 启动kube-apiserver

[root@k8s_master ~]# mv kube-apiserver.service  /usr/lib/systemd/system/
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl enable kube-apiserver
[root@k8s_master ~]# systemctl start kube-apiserver
[root@k8s_master ~]# systemctl status kube-apiserver

3.4.6 配置和启动kube-controller-manager
3.4.6.1 创建kube-controller-manager 的systemd unit 文件

cat > kube-controller-manager.service <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/root/local/bin/kube-controller-manager \\
  --address=127.0.0.1 \\
  --master=http://${MASTER_IP}:8080 \\
  --allocate-node-cidrs=true \\
  --service-cluster-ip-range=${SERVICE_CIDR} \\
  --cluster-cidr=${CLUSTER_CIDR} \\
  --cluster-name=kubernetes \\
  --cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem \\
  --cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem \\
  --service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem \\
  --root-ca-file=/etc/kubernetes/ssl/ca.pem \\
  --leader-elect=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

 --address 值必须为 127.0.0.1,因为当前 kube-apiserver 期望 scheduler 和 controller-manager 在同一台机器
kubectl get componentstatuses
NAME STATUS MESSAGE ERROR
controller-manager Unhealthy Get http://127.0.0.1:10252/healthz: dial tcp 127.0.0.1:10252: getsockopt: connection refused
scheduler Unhealthy Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: getsockopt: connection refused
 --master=http://{MASTER_IP}:8080:使用非安全 8080 端口与 kube-apiserver 通信
 --cluster-cidr 指定 Cluster 中 Pod 的 CIDR 范围,该网段在各 Node 间必须路由可达(flanneld保证)
 --service-cluster-ip-range 参数指定 Cluster 中 Service 的CIDR范围,该网络在各 Node 间必须路由不可达,必须和 kube-apiserver 中的参数一致
 --cluster-signing-* 指定的证书和私钥文件用来签名为 TLS BootStrap 创建的证书和私钥
 --root-ca-file 用来对 kube-apiserver 证书进行校验,指定该参数后,才会在Pod 容器的 ServiceAccount 中放置该 CA 证书文件
 --leader-elect=true 部署多台机器组成的 master 集群时选举产生一处于工作状态的 kube-controller-manager 进程
3.4.6.2 启动kube-controller-manager

[root@k8s_master ~]# mv kube-controller-manager.service /usr/lib/systemd/system/
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl start kube-controller-manager
[root@k8s_master ~]# systemctl status kube-controller-manager
[root@k8s_master ~]# systemctl enable kube-controller-manager

3.4.7 配置和启动kube-scheduler
3.4.7.1 创建kube-scheduler 的systemd unit文件

cat > kube-scheduler.service <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/usr/bin/kube-scheduler \\
  --address=127.0.0.1 \\
  --master=http://${MASTER_IP}:8080 \\
  --leader-elect=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

 --address 值必须为 127.0.0.1,因为当前 kube-apiserver 期望 scheduler 和 controller-manager 在同一台机器
 --master=http://${MASTER_URL}:使用http(非安全端口)与 kube-apiserver 通信
 --leader-elect=true 部署多台机器组成的 master 集群时选举产生一处于工作状态的 kube-controller-manager 进程
3.4.7.2 启动kube-scheduler

[root@k8s_master ~]# mv kube-scheduler.service /usr/lib/systemd/system
[root@k8s_master ~]# systemctl daemon-reload
[root@k8s_master ~]# systemctl start kube-scheduler
[root@k8s_master ~]# systemctl status kube-scheduler
[root@k8s_master ~]# systemctl enable kube-scheduler

3.4.7.3 验证master 节点

[root@k8s_master ~]# kubectl get componentstatuses
NAME                 STATUS    MESSAGE              ERROR
scheduler            Healthy   ok                   
controller-manager   Healthy   ok                   
etcd-0               Healthy   {"health": "true"}   

3.5 部署Node 节点
3.5.1 kubernetes Node 节点包含如下组件:
 flanneld
 docker
 kubelet
 kube-proxy
3.5.2 环境变量

[root@k8s_slave ~]# source /usr/local/bin/env.sh
[root@k8s_slave ~]# export KUBE_APISERVER="https://10.0.0.190:6443"
[root@k8s_slave ~]# echo $KUBE_APISERVER
https://10.0.0.190:6443
[root@k8s_slave ~]# export NODE_IP=10.0.0.191  #当前部署节点的ip

3.5.3 部署flanneld网络

[root@k8s_slave ~]# mkdir flannel
[root@k8s_slave ~]# wget https://github.com/coreos/flannel/releases/download/v0.9.0/flannel-v0.9.0-linux-amd64.tar.gz
[root@k8s_slave ~]# tar -xzvf flannel-v0.9.0-linux-amd64.tar.gz -C flannel
[root@k8s_slave ~]# cp flannel/{flanneld,mk-docker-opts.sh} /usr/bin

3.5.3.1 创建flanneld的systemd unit 文件

cat > 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=/usr/bin/flanneld \\
  -etcd-endpoints=${ETCD_ENDPOINTS} \\
  -etcd-prefix=${FLANNEL_ETCD_PREFIX}
ExecStartPost=/usr/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=on-failure

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

3.5.3.2 启动flanneld服务

cp flanneld.service /usr/lib/systemd/system/
systemctl daemon-reload
systemctl enable flanneld
systemctl start flanneld
systemctl status flanneld

3.5.4 部署docker
3.5.4.1 下载最新的 docker 二进制文件

[root@k8s_slave ~]# https://download.docker.com/linux/static/stable/x86_64/docker-18.03.1-ce.tgz
[root@k8s_slave ~]# tar -xvf docker-18.03.1-ce.tgz
[root@k8s_slave ~]# cp docker/docker* /usr/bin

3.5.4.2 创建 docker 的 systemd unit 文件

[root@k8s_slave ~]# cat docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io

[Service]
EnvironmentFile=-/run/flannel/docker
ExecStart=/usr/bin/dockerd --log-level=error $DOCKER_NETWORK_OPTIONS
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target

3.5.4.3 启动docker

[root@k8s_slave ~]# mv docker.service /usr/lib/systemd/system/
[root@k8s_slave ~]# systemctl daemon-reload
[root@k8s_slave ~]# systemctl start docker
[root@k8s_slave ~]# systemctl status docker
[root@k8s_slave ~]# systemctl enable docker

 docker 从 1.13 版本开始,可能将 iptables FORWARD chain的默认策略设置为DROP,从而导致 ping 其它 Node 上的 Pod IP 失败,遇到这种情况时,需要手动设置策略为 ACCEPT:

[root@k8s_slave ~]# iptables -P FORWARD ACCEPT

 并且把以下命令写入/etc/rc.local文件中,防止节点重启iptables FORWARD chain的默认策略又还原为DROP

[root@k8s_slave ~]# sleep 60 && /sbin/iptables -P FORWARD ACCEPT

 为了加快 pull image 的速度,可以使用国内的仓库镜像服务器,同时增加下载的并发数。(如果 dockerd 已经运行,则需要重启 dockerd 生效。)

[root@k8s_slave ~]# cat /etc/docker/daemon.json
{
"max-concurrent-downloads": 10
}

3.5.5 安装和配置kubelet
3.5.5.1 从master上面拷贝证书文件到slave

[root@k8s_master kubernetes]# scp -r ./* 10.0.0.191:/etc/kubernetes/

 kubelet 启动时向kube-apiserver 发送TLS bootstrapping 请求,需要先将bootstrap token 文件中的kubelet-bootstrap 用户赋予system:node-bootstrapper 角色,然后kubelet 才有权限创建认证请求(certificatesigningrequests):

[root@k8s_slave kubernetes]# kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap
clusterrolebinding "kubelet-bootstrap" created

说明:–user=kubelet-bootstrap 是文件 /etc/kubernetes/token.csv 中指定的用户名,同时也写入了文件 /etc/kubernetes/bootstrap.kubeconfig
 另外1.8 版本中还需要为Node 请求创建一个RBAC 授权规则:

[root@k8s_slave kubernetes]# kubectl create clusterrolebinding kubelet-nodes --clusterrole=system:node --group=system:nodes
clusterrolebinding "kubelet-nodes" created

3.5.5.2 下载最新的kubelet 和kube-proxy 二进制文件(前面下载kubernetes 目录下面其实也有)

[root@k8s_slave ~]# wget https://dl.k8s.io/v1.8.2/kubernetes-server-linux-amd64.tar.gz
[root@k8s_slave ~]# tar -xzvf kubernetes-server-linux-amd64.tar.gz
[root@k8s_slave ~]# cd kubernetes
[root@k8s_slave ~]# tar -xzvf  kubernetes-src.tar.gz
[root@k8s_slave ~]# cp -r ./server/bin/{kube-proxy,kubelet} /usr/bin/

3.5.5.3 创建kubelet bootstapping kubeconfig 文件
#以下需要在master上面创建,创建完成后copy到每个node节点即可

[root@k8s_master ~]# mkdir ssl && cd ssl
#设置集群参数
[root@k8s_mster ~]#  kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=bootstrap.kubeconfig
#设置客户端认证参数
[root@k8s_master ~]# kubectl config set-credentials kubelet-bootstrap \
  --token=${BOOTSTRAP_TOKEN} \
  --kubeconfig=bootstrap.kubeconfig
[root@k8s_master ~]# 设置上下文参数
[root@k8s_master ~]# kubectl config set-context default \
  --cluster=kubernetes \
  --user=kubelet-bootstrap \
  --kubeconfig=bootstrap.kubeconfig
#设置默认上下文
[root@k8s_master ~]# kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
[root@k8s_master ~]# mv bootstrap.kubeconfig /etc/kubernetes/
[root@k8s_master ~]# scp bootstrap.kubeconfig 10.0.0.191:/etc/kubernetes/

 --embed-certs 为 true 时表示将 certificate-authority 证书写入到生成的 bootstrap.kubeconfig 文件中;
 设置 kubelet 客户端认证参数时没有指定秘钥和证书,后续由 kube-apiserver 自动生成;
3.5.5.4 创建kubelet 的systemd unit 文件

[root@k8s_slave ssl]# mkdir /var/lib/kubelet  # 必须先创建工作目录
[root@k8s_slave ]# cat > kubelet.service <<EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/usr/bin/kubelet \\
  --address=${NODE_IP} \\
  --hostname-override=${NODE_IP} \\
  --pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest \\
  --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \\
  --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
  --require-kubeconfig \\
  --cert-dir=/etc/kubernetes/ssl \\
  --cluster-dns=${CLUSTER_DNS_SVC_IP} \\
  --cluster-domain=${CLUSTER_DNS_DOMAIN} \\
  --hairpin-mode promiscuous-bridge \\
  --allow-privileged=true \\
  --serialize-image-pulls=false \\
  --fail-swap-on=false \\
  --logtostderr=true \\
  --v=2

Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

 -address 不能设置为 127.0.0.1,否则后续 Pods 访问 kubelet 的 API 接口时会失败,因为 Pods 访问的 127.0.0.1指向自己而不是 kubelet
 如果设置了 --hostname-override 选项,则 kube-proxy 也需要设置该选项,否则会出现找不到 Node 的情况
 --experimental-bootstrap-kubeconfig 指向 bootstrap kubeconfig 文件,kubelet 使用该文件中的用户名和 token 向 kube-apiserver 发送 TLS Bootstrapping 请求
 管理员通过了 CSR 请求后,kubelet 自动在 --cert-dir 目录创建证书和私钥文件(kubelet-client.crt 和 kubelet-client.key),然后写入 --kubeconfig 文件(自动创建 --kubeconfig 指定的文件)
 建议在 --kubeconfig 配置文件中指定 kube-apiserver 地址,如果未指定 --api-servers 选项,则必须指定 --require-kubeconfig 选项后才从配置文件中读取 kue-apiserver 的地址,否则 kubelet 启动后将找不到 kube-apiserver (日志中提示未找到 API Server),kubectl get nodes 不会返回对应的 Node 信息
 --cluster-dns 指定 kubedns 的 Service IP(可以先分配,后续创建 kubedns 服务时指定该 IP),–cluster-domain 指定域名后缀,这两个参数同时指定后才会生效
3.5.5.5 启动kubelet

[root@k8s_slave ~]# mv kubelet.service /usr/lib/systemd/system/
[root@k8s_slave ~]# systemctl daemon-reload
[root@k8s_slave ~]# systemctl start kubelet
[root@k8s_slave ~]# systemctl status kubelet
[root@k8s_slave ~]# systemctl enable kubelet

3.5.5.6 通过kubelet 的TLS 证书请求
kubelet 首次启动时向kube-apiserver 发送证书签名请求,必须通过后kubernetes 系统才会将该 Node 加入到集群。查看未授权的CSR 请求:

[root@k8s_master ~]# kubectl get csr
NAME                                                   AGE       REQUESTOR           CONDITION
node-csr-VME_P37qMAy5qZaFQXIfbkI-L64nSEbUyyvtxYe7EAQ   1m        kubelet-bootstrap   Pending
[root@k8s_master ~]# kubectl get nodes
No resources found.

3.5.5.7 通过CSR 请求:

[root@k8s_master ~]# kubectl certificate approve node-csr-VME_P37qMAy5qZaFQXIfbkI-L64nSEbUyyvtxYe7EAQ
certificatesigningrequest "node-csr-VME_P37qMAy5qZaFQXIfbkI-L64nSEbUyyvtxYe7EAQ" approved
[root@k8s_master kubernetes]# kubectl get nodes
NAME         STATUS    ROLES     AGE       VERSION
10.0.0.191   Ready     <none>    1m        v1.8.3

3.5.5.8 自动生成了kubelet kubeconfig 文件和公私钥:

[root@k8s_slave kubernetes]# ll /etc/kubernetes/kubelet.kubeconfig 
-rw------- 1 root root 2277 Sep 16 03:31 /etc/kubernetes/kubelet.kubeconfig
[root@k8s_slave kubernetes]# ls -l /etc/kubernetes/ssl/kubelet*
-rw-r--r-- 1 root root 1042 Sep 16 03:31 /etc/kubernetes/ssl/kubelet-client.crt
-rw------- 1 root root  227 Sep 16 03:27 /etc/kubernetes/ssl/kubelet-client.key
-rw-r--r-- 1 root root 1107 Sep 16 03:25 /etc/kubernetes/ssl/kubelet.crt
-rw------- 1 root root 1679 Sep 16 03:25 /etc/kubernetes/ssl/kubelet.key

3.5.6 配置kube-proxy(master创建好后copy到slave节点即可)
3.5.6.1 创建kube-proxy 证书签名请求

[root@k8s_master ~]# cd /root/ssl
[root@k8s_master ssl]# cat > kube-proxy-csr.json <<EOF
{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

 CN 指定该证书的 User 为 system:kube-proxy
 kube-apiserver 预定义的 RoleBinding system:node-proxier 将User system:kube-proxy 与 Role system:node-proxier绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
 hosts 属性值为空列表
3.5.6.2 生成kube-proxy 客户端证书和私钥(从master创建后好copy到slave节点)

[root@k8s_master ssl]# cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \
  -ca-key=/etc/kubernetes/ssl/ca-key.pem \
  -config=/etc/kubernetes/ssl/ca-config.json \
  -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
[root@k8s_master ssl]# ls kube-proxy*
kube-proxy.csr  kube-proxy-csr.json  kube-proxy-key.pem  kube-proxy.pem
[root@k8s_master ssl]# scp kube-proxy* 10.0.0.191:/root/ssl/  #从mastet节点拷贝到slave节点
[root@k8s_slave ssl]# mv kube-proxy*.pem /etc/kubernetes/ssl/

3.5.6.3 创建kube-proxy kubeconfig 文件(从master创建后好copy到slave节点)

#设置集群参数
[root@k8s_master ssl]# kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-proxy.kubeconfig
#设置客户端认证参数
[root@k8s_master ssl]# kubectl config set-credentials kube-proxy \
  --client-certificate=/etc/kubernetes/ssl/kube-proxy.pem \
  --client-key=/etc/kubernetes/ssl/kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig
#设置上下文参数
[root@k8s_master ssl]#kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig
[root@k8s_master ssl]# 设置默认上下文
[root@k8s_master ssl]# kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
[root@k8s_master ssl]#mv kube-proxy.kubeconfig /etc/kubernetes/
[root@k8s_master ssl]#scp kube-proxy.kubeconfig 10.0.0.191:/etc/kubernetes/

 设置集群参数和客户端认证参数时 --embed-certs 都为 true,这会将 certificate-authority、client-certificate 和 client-key 指向的证书文件内容写入到生成的 kube-proxy.kubeconfig 文件中
 kube-proxy.pem 证书中 CN 为 system:kube-proxy,kube-apiserver 预定义的 RoleBinding cluster-admin 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
3.5.6.4 创建kube-proxy 的systemd unit 文件

[root@k8s_slave ssl]# mkdir -p /var/lib/kube-proxy  # 必须先创建工作目录
[root@k8s_slave ssl]# cat > kube-proxy.service <<EOF
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
WorkingDirectory=/var/lib/kube-proxy
ExecStart=/usr/bin/kube-proxy \\
  --bind-address=${NODE_IP} \\
  --hostname-override=${NODE_IP} \\
  --cluster-cidr=${CLUSTER_CIDR} \\
  --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \\
  --logtostderr=true \\
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

 --hostname-override 参数值必须与 kubelet 的值一致,否则 kube-proxy 启动后会找不到该 Node,从而不会创建任何 iptables 规则
 --cluster-cidr 必须与 kube-apiserver 的 --service-cluster-ip-range 选项值一致
 kube-proxy 根据 --cluster-cidr 判断集群内部和外部流量,指定 --cluster-cidr 或 --masquerade-all 选项后 kube-proxy 才会对访问 Service IP 的请求做 SNAT
 --kubeconfig 指定的配置文件嵌入了 kube-apiserver 的地址、用户名、证书、秘钥等请求和认证信息
 预定义的 RoleBinding cluster-admin 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
3.5.6.5 启动kube-proxy

[root@k8s_slave ~]# mv kube-proxy.service /usr/lib/systemd/system/
[root@k8s_slave ~]# systemctl daemon-reload
[root@k8s_slave ~]# systemctl start kube-proxy
[root@k8s_slave ~]# systemctl status kube-proxy
[root@k8s_slave ~]# systemctl enable kube-proxy

3.6 验证集群功能
3.6.1 定义yaml 文件

[root@k8s_master nginx]# cat nginx_rc.yaml 
apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx
spec:
   replicas: 1
   selector:
     app: nginx
   template:
     metadata:
       labels:
         app: nginx
     spec:
       containers:
       - name: nginx
         image: nginx
         ports:
         - containerPort: 80

3.6.2 定义service文件

[root@k8s_master nginx]# cat nginx_svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: NodePort
  ports:
   - port: 80
     nodePort: 30006
  selector:
    app: nginx

3.6.2.1 创建nginx服务

[root@k8s_master nginx]# kubectl create -f nginx_rc.yaml
[root@k8s_master nginx]# kubectl create -f nginx_svc.yaml
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

运维那些事~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值