技术交流28群

服务热线

135-6963-3175

微信服务号

k8s源码方式编译安装部署 更新时间 2019-4-22 浏览2325次

Kubernetes1.16 源码编译安装部署

主要步骤概览:

1、下载cfssl在所有节点安装并生成ca根证书(一台生成分发所有节点)

2、etcd集群安装,etcd证书生成和私钥(通过ca根证书生成)、并创建etcd系统服务启动

3、同步源码编译后的二进制文件至所有节点的/usr/local/bin

master节点:

4、master节点安装kubectl命令行工具、admin证书生成和私钥(通过ca根证书生成)、通过kubectl创建kubeconfig配置文件(配置文件可以在      集群中通用下发,也可以每台单独创建)

5、安装flannel网络二进制文件,flanneld证书和私钥生成(通过ca根证书)、向etd写入集群pod网段信息(只需执行一次)、

     并创建flanneld系统服务并启动

6、kube-apiserver证书及私钥生成(通过ca根证书)、创建kube-apiserver使用的客户端token文件、创建kube-apiserver系统服务并启动

7、配置kube-controller-manager系统服务并启动

8、创建kube-scheduler系统服务并启动

9、验证master节点安装情况、system:node权限更改

node节点:

10、node安装flannel网络,参考master flannel(去掉etcd写入步骤)

11、node安装kubectl命令行工具,参考master节点kubectl安装

12、安装配置启动docker、并创建docker系统服务

13、安装配置启动kubelete\通过kubectl创建system:node-bootstrapper 及用户角色绑定(只需第一次执行)

      通过kubectl创建kubelet bootstrapping kubeconfig 文件,创建kubelet系统服务并启动

14、启动后登录master可查看到node资源

15、创建kube-proxy证书及私钥、通过kubectl创建kube-proxy kubeconfig文件、创建kube-proxy系统服务并启动

综上:

master:etcd\kubectl\flanneld\kube-apiserver\kube-controller-manager\kube-scheduler

node:etcd\kubectl\flanneld\docker\kubelete\kube-proxy

涉及证书:ca根证书

              etcd证书

              admin证书

              flanneld证书

              kube-apiserver(kubernetes)证书

              kube-proxy证书

一、kubernetes 源码编译

参考章节kubernetes源码编译 http://www.1json.com/kubernetes/kubernetes-build.html

二、安装部署环境介绍

iphostname角色
192.168.1.104master1master+node+etcd
192.168.1.105
node1node+etcd
192.168.1.106node2node+etcd

查看服务日志工具:journalctl -f -u 服务名,例如:journalctl -f -u kubelet

1、首先关闭所有节点防火墙、selinux

$ systemctl stop firewalld && systemctl disable firewalld
$ setenforce 0
$ vim /etc/selinux/config
SELINUX=disabled

2、关闭所有节点swap分区

$swapoff -a
vim /etc/fstab

3、node+master节点配置host,使主机名可以互相解析

vim /etc/hosts
192.168.1.104 master1
192.168.1.105 node1
192.168.1.106 node2

开启路由转发和iptables对bridge信息进行处理的内核参数

$ cat > /etc/sysctl.d/k8s.conf <<EOF 
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sysctl -p /etc/sysctl.d/k8s.conf

三 k8s集群证书的准备

 kubernetes 系统各组件需要使用 TLS 证书对通信进行加密,本文档使用 CloudFlare 的 PKI 工具集 cfssl 来生成 Certificate Authority (CA) 证书和秘钥文件,CA 是自签名的证书,用来签名后续创建的其它 TLS 证书。

  1. 所有服务器下载并安装cfssl

$ cd ~
$ wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
$ chmod +x cfssl_linux-amd64
$ mv cfssl_linux-amd64 /usr/local/bin/cfssl
 
$ wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
$ chmod +x cfssljson_linux-amd64
$ mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
 
$ wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
$ chmod +x cfssl-certinfo_linux-amd64
$ mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
 
#$ cfssl print-defaults config > config.json  #默认CA配置文件
#$ cfssl print-defaults csr > csr.json        #默认证书请求配置

2、任选一服务器创建k8s项目CA中心并同步到集群所有服务器

创建目录

mkdir -p /etc/kubernetes/ssl
cd /etc/kubernetes/ssl

创建CA证书配置文件

$cat  > ca-config.json   <<EOF 
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "87600h"
      }
    }
  }
}
EOF

ca-config.json:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile;

signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE;

server auth:表示 client 可以用该 CA 对 server 提供的证书进行验证;

client auth:表示 server 可以用该 CA 对 client 提供的证书进行验证;

创建CA根证书签名请求

$cat > ca-csr.json   <<EOF 
{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

"CN":Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name);浏览器使用该字段验证网站是否合法;

"O":Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group);

生成CA中心根证书和密钥

$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca
$ ls ca*
ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem

将证书、密钥、配置文件分发至所有服务器

将/etc/kubernetes/ssl下的文件分发到集群上所有服务器上。

四、etcd集群安装部署

etcd集群是k8s存储各类管理状态数据的一个基础服务。

逐台安装:

1、证书和etcd配置注意:

#关闭防火墙
sytemctl stop firewalld
#时钟同步
ntpdate cn.pool.ntp.org

2、下载并安装etcd

$ wget https://github.com/coreos/etcd/releases/download/v3.2.9/etcd-v3.2.9-linux-amd64.tar.gz
$ tar -xvf etcd-v3.2.9-linux-amd64.tar.gz
$ mv etcd-v3.2.9-linux-amd64/etcd* /usr/local/bin

3、创建etcd使用的密钥和证书

3.1创建证书签名

$ cat > etcd-csr.json <<EOF
{
  "CN": "etcd",
  "hosts": [
    "127.0.0.1",
    "192.168.1.104"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

  hosts必须带上。当前机器的ip。

生成etcd的证书和私钥

$ 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 etcd-csr.json | cfssljson -bare etcd
$ ls etcd*
etcd.csr  etcd-csr.json  etcd-key.pem etcd.pem
$ mkdir -p /etc/etcd/ssl
$ mv etcd*.pem /etc/etcd/ssl
$ rm etcd.csr  etcd-csr.json

创建etcd系统服务并启动

$ mkdir -p /var/lib/etcd  # 必须先创建工作目录
$ 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/local/bin/etcd \\
  --name=etcd-host0 \\
  --cert-file=/etc/etcd/ssl/etcd.pem \\
  --key-file=/etc/etcd/ssl/etcd-key.pem \\
  --peer-cert-file=/etc/etcd/ssl/etcd.pem \\
  --peer-key-file=/etc/etcd/ssl/etcd-key.pem \\
  --trusted-ca-file=/etc/kubernetes/ssl/ca.pem \\
  --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem \\
  --initial-advertise-peer-urls=https://192.168.1.104:2380 \\
  --listen-peer-urls=https://192.168.1.104:2380 \\
  --listen-client-urls=https://192.168.1.104:2379,http://127.0.0.1:2379 \\
  --advertise-client-urls=https://192.168.1.104:2379 \\
  --initial-cluster-token=etcd-cluster-0 \\
  --initial-cluster=etcd-host0=https://192.168.1.104:2380,etcd-host1=https://192.168.1.105:2380,etcd-host2=https://192.168.1.106:2380 \\
  --initial-cluster-state=new \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF

--name=etcd-host0 : 当前部署的机器名称(随便定义,只要能区分不同机器即可)

启动服务

$ mv etcd.service /etc/systemd/system/
$ systemctl daemon-reload
$ systemctl enable etcd
$ systemctl start etcd
$ systemctl status etcd

验证:

[root@localhost etcd]# for ip in {192.168.1.104 192.168.1.105 192.168.1.106}; do
>   ETCDCTL_API=3 /usr/local/bin/etcdctl \
>   --endpoints=https://${ip}:2379  \
>   --cacert=/etc/kubernetes/ssl/ca.pem \
>   --cert=/etc/etcd/ssl/etcd.pem \
>   --key=/etc/etcd/ssl/etcd-key.pem \
>   endpoint health; done
https://192.168.1.104:2379 is healthy: successfully committed proposal: took = 14.563606ms
https://192.168.1.105:2379 is healthy: successfully committed proposal: took = 13.623491ms
https://192.168.1.106:2379 is healthy: successfully committed proposal: took = 12.989808ms
[root@localhost etcd]#

在部署etcd集群时,尝试启动etcd1时,若出现报错:

Apr 12 01:06:49 k8s-master etcd[3092]: health check for peer 618d69366dd8cee3 could not connect: dial tcp 192.168.81.12:2380: getsockopt: connection refused
Apr 12 01:06:49 k8s-master etcd[3092]: health check for peer acd2ba924953b1ec could not connect: dial tcp 192.168.81.60:2380: getsockopt: connection refused
Apr 12 01:06:48 k8s-master etcd[3092]: publish error: etcdserver: request timed out

分析是因为etcd1的配置文件/etc/etcd/etcd.conf中的ETCD_INITIAL_CLUSTER_STATE是new,而在配置中ETCD_INITIAL_CLUSTER写入了etcd2/3的IP:PORT,这时etcd1尝试去连接etcd2、etcd3,但是etcd2、3的etcd服务此时还未启动,因此需要先启动etcd2和3的etcd服务,再去启动etcd1。

--initial-cluster-token=etcd-cluster-0要一致

五、master节点安装部署

1、安装kubectl命令行工具

kubectl 默认从 ~/.kube/config 配置文件获取访问 kube-apiserver 地址、证书、用户名等信息,如果没有配置该文件,执行命令时出错。

步骤一源码编译产生的二进制文件:

mv bin/{kube-apiserver,kube-controller-manager,kube-scheduler,kubectl,kube-proxy,kubelet} /usr/local/bin

创建kubectl使用的admin证书

$ 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

admin证书说明:

 后续 kube-apiserver 使用 RBAC 对客户端(如 kubelet、kube-proxy、Pod)请求进行授权;

 kube-apiserver 预定义了一些 RBAC 使用的 RoleBindings,如 cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予了调用kube-apiserver 所有 API的权限;

 O 指定该证书的 Group 为 system:masters,kubelet 使用该证书访问 kube-apiserver 时 ,由于证书被 CA 签名,所以认证通过,同时由于证书用户组为经过预授权的 system:masters,所以被授予访问所有 API 的权限;

kubectl的kubeconfig配置文件

# 设置集群参数 --server为KUBE-APISERVER,--embed-certs=true的作用是不在配置文件中显示证书信息。
[root@master1 app]# kubectl config set-cluster kubernetes \
   --certificate-authority=/etc/kubernetes/ssl/ca.pem \
   --embed-certs=true \
   --server=https://192.168.1.104:6443
Cluster "kubernetes" set.
# 设置客户端认证参数
[root@master1 app]# kubectl config set-credentials admin \
   --client-certificate=/etc/kubernetes/ssl/admin.pem \
   --embed-certs=true \
   --client-key=/etc/kubernetes/ssl/admin-key.pem
User "admin" set.
# 设置上下文参数
[root@master1 app]# kubectl config set-context kubernetes \
   --cluster=kubernetes \
   --user=admin
Context "kubernetes" created.
# 设置默认上下文
[root@master1 app]# kubectl config use-context kubernetes
Switched to context "kubernetes".
[root@master1 app]#

admin.pem 证书 O 字段值为 system:masters,kube-apiserver 预定义的 RoleBinding cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予了调用kube-apiserver 相关 API 的权限;

生成的 kubeconfig 被保存到 ~/.kube/config 文件(配置文件可以在集群通用下发,也可以每个节点单独创建);

2、安装部署flannel网络

2.1 创建证书请求文件并生成证书和私钥

$ cat > flanneld-csr.json <<EOF 
{
  "CN": "flanneld",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF
 
$ 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 flanneld-csr.json | cfssljson -bare flanneld
$ ls flanneld*
flanneld.csr  flanneld-csr.json  flanneld-key.pem flanneld.pem
$ mkdir -p /etc/flanneld/ssl
$ mv flanneld*.pem /etc/flanneld/ssl
$ rm flanneld.csr  flanneld-csr.json

2.2 向etcd写入集群pod网段信息(本步只需第一次执行)

$ etcdctl \
  --endpoints=https://192.168.1.104:2379,https://192.168.1.105:2379,https://192.168.1.106:2379 \
  --ca-file=/etc/kubernetes/ssl/ca.pem \
  --cert-file=/etc/flanneld/ssl/flanneld.pem \
  --key-file=/etc/flanneld/ssl/flanneld-key.pem \
  set /kubernetes/network/config '{"Network":"'172.30.0.0/16'", "SubnetLen": 24, "Backend": {"Type": "vxlan"}}'

flanneld 目前版本 (v0.9.0) 不支持 etcd v3,故使用 etcd v2 API 写入配置 key 和网段数据;

写入的 Pod 网段(172.30.0.0/16)(部署前路由不可达,**部署后**路由可达(flanneld保证),最好使用主机未用的网段)必须与 kube-controller-manager 的 --cluster-cidr 选项值一致;

flannel v0.11版本不支持etcd v3.4.3版本,支持etcd v3.3.10-版本。


2.3 下载安装二进制文件

$ mkdir flannel
$ wget https://github.com/coreos/flannel/releases/download/v0.9.0/flannel-v0.9.0-linux-amd64.tar.gz
$ tar -xf flannel-v0.9.0-linux-amd64.tar.gz -C flannel
$ ls flannel
flanneld  mk-docker-opts.sh  README.md
$ mv  flannel/*  /usr/local/bin

2.4 创建flannel系统服务并启动

$ 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/local/bin/flanneld \\
  -etcd-cafile=/etc/kubernetes/ssl/ca.pem \\
  -etcd-certfile=/etc/flanneld/ssl/flanneld.pem \\
  -etcd-keyfile=/etc/flanneld/ssl/flanneld-key.pem \\
  -etcd-endpoints=https://192.168.1.104:2379,https://192.168.1.105:2379,https://192.168.1.106:2379 \\
  -etcd-prefix=/kubernetes/network
ExecStartPost=/usr/local/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
 
$ cp flanneld.service /etc/systemd/system/
$ systemctl daemon-reload
$ systemctl enable flanneld
$ systemctl start flanneld
$ systemctl status flanneld

-etcd-prefix:存放flanneld配置文件的Etcd存储中的路径

mk-docker-opts.sh 脚本将分配给 flanneld 的 Pod 子网网段信息写入到 /run/flannel/docker 文件中,后续 docker 启动时使用这个文件中参数值设置 docker0 网桥;

 flanneld 使用系统缺省路由所在的接口和其它节点通信,对于有多个网络接口的机器(如,内网和公网),可以用 --iface 选项值指定通信接口(上面的 systemd unit 文件没指定这个选项),如本着 Vagrant + Virtualbox,就要指定--iface=enp0s8;

2.5 检查分配给各flanneld的pod网段信息

$ # 查看集群 Pod 网段(/16)
$ etcdctl \
  --endpoints=https://192.168.1.104:2379,https://192.168.1.105:2379,https://192.168.1.106:2379 \
  --ca-file=/etc/kubernetes/ssl/ca.pem \
  --cert-file=/etc/flanneld/ssl/flanneld.pem \
  --key-file=/etc/flanneld/ssl/flanneld-key.pem \
  get /kubernetes/network/config
$ # 查看已分配的 Pod 子网段列表(/24)
$ etcdctl \
  --endpoints=https://192.168.1.104:2379,https://192.168.1.105:2379,https://192.168.1.106:2379 \
  --ca-file=/etc/kubernetes/ssl/ca.pem \
  --cert-file=/etc/flanneld/ssl/flanneld.pem \
  --key-file=/etc/flanneld/ssl/flanneld-key.pem \
  ls /kubernetes/network/subnets
$ # 查看某一 Pod 网段对应的 flanneld 进程监听的 IP 和网络参数
$ etcdctl \
  --endpoints=https://192.168.1.104:2379,https://192.168.1.105:2379,https://192.168.1.106:2379 \
  --ca-file=/etc/kubernetes/ssl/ca.pem \
  --cert-file=/etc/flanneld/ssl/flanneld.pem \
  --key-file=/etc/flanneld/ssl/flanneld-key.pem \
  get /kubernetes/network/subnets/172.30.19.0-24

3 配置启动kube-apiserver

创建kubernetes证书

$ cat > kubernetes-csr.json <<EOF
{
  "CN": "kubernetes",
  "hosts": [
    "127.0.0.1",
    "192.168.1.104", 
    "10.254.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": "System"
    }
  ]
}
EOF
 
$ 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
$ ls kubernetes*
kubernetes.csr  kubernetes-csr.json  kubernetes-key.pem  kubernetes.pem
$ mkdir -p /etc/kubernetes/ssl/
$ mv kubernetes*.pem /etc/kubernetes/ssl/
$ rm kubernetes.csr  kubernetes-csr.json

192.168.1.104为k8s master地址

10.254.0.1服务ip (一般是 服务ip网段的第一个IP)


host必须写,否则kubectl不生效

创建kube-apiserver使用的客户端token文件

kubelet 首次启动时向 kube-apiserver 发送 TLS Bootstrapping 请求,kube-apiserver 验证 kubelet 请求中的 token 是否与它配置的 token.csv 一致,如果一致则自动为 kubelet生成证书和秘钥。文件中的token: 51f7e4ba8b7be874fcff18bf5cf41a7d是TLS Bootstrapping 使用的 Token,可以使用命令 head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成

$ cat > token.csv <<EOF
51f7e4ba8b7be874fcff18bf5cf41a7d,kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
$ mv token.csv /etc/kubernetes/

创建kube-apiserver系统服务并启动

$ cat > kube-apiserver.service <<EOF  
[Unit]

Description=Kubernetes API Server

Documentation=https://github.com/GoogleCloudPlatform/kubernetes

After=network.target

[Service]

ExecStart=/usr/local/bin/kube-apiserver \\
  --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
  --advertise-address=192.168.1.104 \\
  --bind-address=192.168.1.104 \\
  --insecure-bind-address=192.168.1.104 \\
  --authorization-mode=RBAC \\
  --runtime-config=rbac.authorization.k8s.io/v1alpha1 \\
  --kubelet-https=true \\
  --enable-bootstrap-token-auth \\
  --token-auth-file=/etc/kubernetes/token.csv \\
  --service-cluster-ip-range=10.254.0.0/16 \\
  --service-node-port-range=8400-9000 \\
  --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=https://192.168.1.104:2379,https://192.168.1.105:2379,https://192.168.1.106: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/lib/audit.log \\
  --event-ttl=1h \\
  --v=2
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF

$ cp kube-apiserver.service /etc/systemd/system/
$ systemctl daemon-reload
$ systemctl enable kube-apiserver
$ systemctl start kube-apiserver
$ systemctl status kube-apiserver

--advertise-address={MASTER_IP}

--bind-address={MASTER_IP}

--insecure-bind-address={MASTER_IP}

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 CIDR),部署前路由不可达,部署后集群内使用IP:Port可达;(最好使用 主机未用的网段)

 --service-node-port-range=8400-9000 指定 NodePort 的端口范围;

 缺省情况下 kubernetes 对象保存在 etcd /registry 路径下,可以通过 --etcd-prefix 参数进行调整;

4 配置启动kube-controller-manager

$ cat <<EOF > kube-controller-manager.service 
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
  --address=127.0.0.1 \\
  --master=http://192.168.1.104:8080 \\
  --allocate-node-cidrs=true \\
  --service-cluster-ip-range=10.254.0.0/16 \\
  --cluster-cidr=172.30.0.0/16 \\
  --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
 
$ cp kube-controller-manager.service /etc/systemd/system/
$ systemctl daemon-reload
$ systemctl enable kube-controller-manager
$ systemctl start kube-controller-manager

--address 值必须为 127.0.0.1,因为当前 kube-apiserver 期望 scheduler 和 controller-manager 在同一台机器;

--master=http://{MASTER_IP}:8080:使用非安全 8080 端口与 kube-apiserver 通信;

--cluster-cidr 指定 Cluster 中 Pod 的 CIDR 范围,该网段在各 Node 间必须路由可达(flanneld保证);

                     (172.30.0.0/16)(部署前路由不可达,**部署后**路由可达(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 进程;

5 配置和启动 kube-scheduler

$ cat > kube-scheduler.service <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
  --address=127.0.0.1 \\
  --master=http://192.168.1.104:8080 \\
  --leader-elect=true \\
  --v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
 
$ cp kube-scheduler.service /etc/systemd/system/
$ systemctl daemon-reload
$ systemctl enable kube-scheduler
$ systemctl start kube-scheduler

--address 值必须为 127.0.0.1,因为当前 kube-apiserver 期望 scheduler 和 controller-manager 在同一台机器;

--master=http://{MASTER_IP}:8080:使用非安全 8080 端口与 kube-apiserver 通信;

--leader-elect=true 部署多台机器组成的 master 集群时选举产生一处于工作状态的 kube-controller-manager 进程;

验证master节点安装情况

[root@master1 ~]# kubectl get cs
NAME                 AGE
controller-manager   <unknown>
scheduler            <unknown>
etcd-2               <unknown>
etcd-0               <unknown>
etcd-1               <unknown>
#k8s 1.16 版本有 bug,kubectl get cs 会显示全部 unknown,要 kubectl get cs -o yaml
$ kubectl get svc

system:node权限问题更改,否则会造成node无法注册kube-apiserver(Unable to register node)

kubectl set subject clusterrolebinding system:node --group=system:nodes

六 k8s的node节点安装部署

1、安装部署flannel网络,参考master节点flannel安装,去调etcd写入步骤

2、复制k8s6个组件到/usr/local/bin

3、安装kubectl命令行工具

4、安装配置启动docker

也可参考docker安装章节

或者下面步骤

$ wget https://download.docker.com/linux/centos/docker-ce.repo
$ mv  docker-ce.repo  /etc/yum.repos.d/
$ yum clean all && yum makecache
$ yum install docker-ce-17.09.0.ce  -y

创建docker系统服务

$ vim docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io
 
[Service]
Environment="PATH=/root/local/bin:/bin:/sbin:/usr/bin:/usr/sbin"
EnvironmentFile=-/run/flannel/docker
ExecStartPost=/sbin/iptables -I FORWARD -s 0.0.0.0/0 -j ACCEPT
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.targe
 
$ cp docker.service /etc/systemd/system/docker.service
$ systemctl daemon-reload
$ systemctl enable docker
$ systemctl start dockerdockerd 运行时会调用其它 docker 命令,如 docker-proxy,所以需要将 docker 命令所在的目录加到 PATH 环境变量中;

 flanneld 启动时将网络配置写入到 /run/flannel/docker 文件中的变量 DOCKER_NETWORK_OPTIONS,dockerd 命令行上指定该变量值来设置 docker0 网桥参数;

如果指定了多个 EnvironmentFile 选项,则必须将 /run/flannel/docker 放在最后(确保 docker0 使用 flanneld 生成的 bip 参数);

不能关闭默认开启的 --iptables 和 --ip-masq 选项;

如果内核版本比较新,建议使用 overlay 存储驱动;

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


5 安装配置启动kubelete

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

$ kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap

--user=kubelet-bootstrap是文件 /etc/kubernetes/token.csv 中指定的用户名,同时也写入了文件 /etc/kubernetes/bootstrap.kubeconfig;

创建 kubelet bootstrapping kubeconfig 文件

$ # 设置集群参数--server=kube_apiserver地址
$ kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=https://192.168.1.104:6443 \
  --kubeconfig=bootstrap.kubeconfig
$ # 设置客户端认证参数
  #文件中的token:51f7e4ba8b7be874fcff18bf5cf41a7d是TLS Bootstrapping 使用的 Token,
  #可以使用命令 head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成,不过要与apiserver端的一致
$ kubectl config set-credentials kubelet-bootstrap \
  --token=51f7e4ba8b7be874fcff18bf5cf41a7d \
  --kubeconfig=bootstrap.kubeconfig
$ # 设置上下文参数
$ kubectl config set-context default \
  --cluster=kubernetes \
  --user=kubelet-bootstrap \
  --kubeconfig=bootstrap.kubeconfig
$ # 设置默认上下文
$ kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
$ mv bootstrap.kubeconfig /etc/kubernetes/

注:/etc/kubernetes/bootstrap.kubeconfig在node节点中可以集群通用,集中下发。

创建kubelet的系统服务并启动

$ mkdir /var/lib/kubelet # 必须先创建工作目录
$ cat  <<EOF > kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
 
[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/usr/local/bin/kubelet \\
  --address=192.168.1.104 \\
  --pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest \\
  --bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \\
  --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
  --cert-dir=/etc/kubernetes/ssl \\
  --cluster-dns=10.254.0.2 \\
  --cluster-domain=cluster.local \\
  --hairpin-mode promiscuous-bridge \\
  --serialize-image-pulls=false \\
  --logtostderr=true \\
  --v=2
ExecStartPost=/sbin/iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -s 172.16.0.0/12 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -s 192.168.0.0/16 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -p tcp --dport 4194 -j DROP
Restart=on-failure
RestartSec=5
 
[Install]
WantedBy=multi-user.target
EOF
 
$ cp kubelet.service /etc/systemd/system/kubelet.service
$ systemctl daemon-reload
$ systemctl enable kubelet
$ systemctl start kubelet
$ systemctl status kubelet

注:上面命令中去掉了--allow-privileged=true和--require-kubeconfig 部分参数在1.16已被废弃

--cluster-dns=10.254.0.2 集群 DNS 服务 IP (从 服务网段中预分配)

--cluster-domain=cluster.local集群dns域名

--address=当前机器节点ip

--experimental-bootstrap-kubeconfig已弃用,使用 --bootstrap-kubeconfig 参数

如果指定的--kubeconfig不存在,将使用bootstrp-kubeconfig从apiserver获取客户端证书,成功后将私钥和证书生成的kubeconfig文件写入--kubecofnig指定的路径,证书和私钥写入--cert-dir指定的路径

启动后登陆master1节点操作

$kubectl get csr
$kubectl certificate approve xxxx
$kubectl get node -o wide

6 安装配置启动kube-proxy

创建kube-proxy证书

$ cat  <<EOF > kube-proxy-csr.json
{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF
 
$ 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
$ ls kube-proxy*
kube-proxy.csr  kube-proxy-csr.json  kube-proxy-key.pem  kube-proxy.pem
$ mv kube-proxy*.pem /etc/kubernetes/ssl/
$ rm kube-proxy.csr  kube-proxy-csr.json

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 属性值为空列表;

创建kube-proxy kubeconfig文件

$ # 设置集群参数 --server为kube-apiserver地址
$ kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=https://192.168.1.104:6443 \
  --kubeconfig=kube-proxy.kubeconfig
$ # 设置客户端认证参数
$ 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
$ # 设置上下文参数
$ kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig
$ # 设置默认上下文
$ kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
$ mv kube-proxy.kubeconfig /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 的权限;

创建kube-proxy系统服务并启动

 $ mkdir -p /var/lib/kube-proxy # 必须先创建工作目录
$ cat <<EOF  > kube-proxy.service
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
 
[Service]
WorkingDirectory=/var/lib/kube-proxy
ExecStart=/usr/local/bin/kube-proxy \\
  --bind-address=192.168.1.104 \\
  --cluster-cidr=10.254.0.0/16 \\
  --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \\
  --logtostderr=true \\
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
 
[Install]
WantedBy=multi-user.target
EOF
 
$ cp kube-proxy.service /etc/systemd/system/
$ systemctl daemon-reload
$ systemctl enable kube-proxy
$ systemctl start kube-proxy
$ systemctl status kube-proxy

--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 的权限;

--bind-address=当前节点ip

$netstat -anlpt |grep LISTEN |grep kube
$kubectl get nodes


附:

假如需要pod之前可以互相通信,需要安装coredns插件,创建coredns.yml

[root@master1 1]# cat coredns.yml 
# Warning: This is a file generated from the base underscore template file: coredns.yaml.base
apiVersion: v1
kind: ServiceAccount
metadata:
  name: coredns
  namespace: kube-system
  labels:
      kubernetes.io/cluster-service: "true"
      addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
    addonmanager.kubernetes.io/mode: Reconcile
  name: system:coredns
rules:
- apiGroups:
  - ""
  resources:
  - endpoints
  - services
  - pods
  - namespaces
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
    addonmanager.kubernetes.io/mode: EnsureExists
  name: system:coredns
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:coredns
subjects:
- kind: ServiceAccount
  name: coredns
  namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
  labels:
      addonmanager.kubernetes.io/mode: EnsureExists
data:
  Corefile: |
    .:53 {
        errors
        health
        kubernetes cluster.local  in-addr.arpa ip6.arpa {  #cluster.local集群域名
            pods insecure
            upstream
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "CoreDNS"
spec:
  # replicas: not specified here:
  # 1. In order to make Addon Manager do not reconcile this replicas parameter.
  # 2. Default is 1.
  # 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels:
      k8s-app: kube-dns
  template:
    metadata:
      labels:
        k8s-app: kube-dns
      annotations:
        seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
    spec:
      priorityClassName: system-cluster-critical
      serviceAccountName: coredns
      tolerations:
        - key: "CriticalAddonsOnly"
          operator: "Exists"
      nodeSelector:
        beta.kubernetes.io/os: linux
      containers:
      - name: coredns
        image: registry-intl.cn-hangzhou.aliyuncs.com/gcr-connor/coredns:1.3.1
        imagePullPolicy: IfNotPresent
        resources:
          limits:
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 70Mi
        args: [ "-conf", "/etc/coredns/Corefile" ]
        volumeMounts:
        - name: config-volume
          mountPath: /etc/coredns
          readOnly: true
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
        - containerPort: 9153
          name: metrics
          protocol: TCP
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - all
          readOnlyRootFilesystem: true
      dnsPolicy: Default
      volumes:
        - name: config-volume
          configMap:
            name: coredns
            items:
            - key: Corefile
              path: Corefile
---
apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  annotations:
    prometheus.io/port: "9153"
    prometheus.io/scrape: "true"
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "CoreDNS"
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 10.254.0.2   #修改集群的IP
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP
  - name: metrics
    port: 9153
    protocol: TCP
[root@master1 1]# kubectl apply -f coredns.yml

然后验证查看:

[root@master1 1]# kubectl get pods,svc -A              
NAMESPACE       NAME                                           READY   STATUS    RESTARTS   AGE
default         pod/busybox                                    1/1     Running   0          58m
kube-system     pod/coredns-7569d87499-qmpsm                   1/1     Running   0          10m
NAMESPACE       NAME                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                    AGE
kube-system     service/kube-dns         ClusterIP   10.254.0.2       <none>        53/UDP,53/TCP,9153/TCP     17m
[root@master1 1]#