MENU

Kubernetes入门:高可用集群搭建

2019 年 03 月 04 日 • 应用服务器

Kubernetes简介

简称K8S,是Google在2014年6月开源的一个容器集群管理系统,K8S主要用于自动化部署、扩展和管理容器应用,提供了资源调度、部署管理、服务发现、扩容缩容、监控等一套功能,Kubernetes目标是让部署容器化应用更简单。

本篇文章只是将Kubernetes高可用集群搭建起来,并没有涉及到太多Kubernetes的操作和理论方面的东西,Kubernetes真的很复杂,无论是搭建还是使用,下面开始吧。

Kubernetes 概述

Kubernetes是什么

  • 是Google在2014年开源的一个容器集群管理系统,简称K8S
  • K8S用于容器化应用程序的部署,扩展和管理
  • K8S提供了容器编排、资源调度、弹性伸缩、部署管理、服务发现等一系列功能。
  • Kubernetes目标是让部署容器化应用简单高效
  • 官方网站:https://kubernetes.io/

Kubernetes特性

自我修复

在节点故障时重新启动失败的容器,替换和重新部署,保证预期的副本数量,杀死健康检查失败的容器,并且在未准备好之前不会处理客户端请求,确保线上服务不中断

弹性伸缩

使用命令、UI或者基于CPU使用情况自动快速扩容和缩容程序实例,确保应用服务高峰并发时的高可用性,业务低峰时回收资源,以最小成本运行服务,这个比较流啤

自动部署和回滚

K8S采用滚动更新策略更新应用,一次更新一个Pod,如果过程中出现问题,将回滚更改,保证升级不会影响业务

服务发现和负载均衡

K8S为多个容器提供一个统一访问入口(内部IP地址和一个DNS名称),并且负载均衡关联所有容器,是用户无需考虑容器IP问题。

机密和配置管理

管理机密数据和应用程序配置,而不需要把敏感数据暴露在镜像里,提高敏感数据安全性,并可以将一些常用的配置存储在K8S里,方便应用程序使用。

存储编排

挂载外部存储系统,无论是来自本地存储,公有云,还是网络存储(如NFS)都作为集群资源的一部分使用,极大提高存储使用的灵活性。

批处理

提供一次性任务,定时任务,满足批量数据处理和分析场景。

Kubernetes集群架构与组件

图左为master节点,类似swarmManager节点,Master有三个组件,分别为API Serverschedulercontroller-manager。分别介绍一下。

master组件
  • kube-apiserver

    • Kubernetes API 集群统一入口,各组件协调者,以RESTful API 提供接口服务,所有对象资源的增删改查和监听都交给APIServer处理后在提交给Etcd存储
  • kube-controller-manager

    • 处理集群中常规后台任务,一个资源对应一个控制器,而Controller Manager 就是负责管理这些控制器的。
  • kube-scheduler

    • 根据调度算法为新创建的Pod选择一个Node节点,可以任意部署,可以部署在同一个节点上,也可以部署在不同的节点上。
  • etcd

    • 分布式键值存储系统,用户保存集群状态数据,比如PodService等对象信息
Node组件
  • kubelet

    • MasterNode节点上的Agent,管理本机运行容器的生命周期,如创建容器,Pod挂载数据卷,下载secret、获取容器和节点状态等工作,kubelet将每个Pod转换成一组容器
  • kube-proxy

    • Node节点上实现Pod网络代理,维护网络规则和四层负载均衡工作。
  • docker 或 rocket

    • 容器引擎,运行容器

Kubernetes核心概念

  • Pod

    • 最小部署单元
    • 一组容器的集合
    • 一个Pod中的容器共享网络命名空间
    • Pod是短暂的
  • Controllers

    • ReplicaSet:确保预期的Pod副本数量
    • Deployment:无状态应用部署
    • StatefulSet:有状态应用部署
    • DaenonSet:确保所有的Node运行同一个Pod
    • Job:一次性任务
    • Cronjob:定时任务
    • 更高层次对象,部署和管理Pod
  • Service

    • 防止Pod失联
    • 定义一组Pod访问策略
  • Label

    • 标签,附加到某个资源上,用于关联对象,查询和筛选
  • Namespaces

    • 命名空间,将对象逻辑上隔离
  • Annotations

    • 注释

理论暂时就这些,下面开始部署Kubernetes集群

环境规划

暂时决定使用七台虚拟机,两个Manager节点,三个Node节点,软件使用最新稳定版,包括系统,软件版本如下。

软件版本
Linux操作系统CentOS7.6_X64
Kubernetes1.12.6
docker-ce18.09.2
Etcd3.3.12
Flannel0.11

节点规划

角色IP组件
mater-01192.168.1.200kube-apiserver
kube-controller-manager
kuber-scheduler
etcd
mater-02192.168.1.201kube-apiserver
kube-controller-manager
kuber-scheduler
etcd
node-01192.168.1.202kunelet
kube-proxy
docker
flannel
etcd
node-02192.168.1.203kunelet
kube-proxy
docker
flannel
etcd
node-03192.168.1.204kunelet
kube-proxy
docker
flannel
Load Balancer Master192.168.1.205
192.168.1.207 (VIP)
Nginx L4
Load Balancer Backup192.168.1.206Nginx L4

许多组件都介绍过了,还有一个flannel,提供K8S集群网络,所有Node节点都要安装,etcd装三个是要做高可用,正常来说etcd不会安装在K8S服务器中,会单拎出来,测试环境就这样吧。

Etcd集群部署阶段

自签Etcd证书

需要使用一个工具,叫做cfssl,官方工具,很方便,先为Etcd&flannel准备一套证书,一共需要两套证书,上述两个组件使用一套,kube-apiserver&kubelet&kube-proxy&kubectl公用一套,操作如下,我就在master-01进行生成了。

[root@master-1 ~]# mkdir -p /usr/local/kubernetes/certs/etcd
[root@master-1 ~]# cd /usr/local/kubernetes/certs/etcd/
[root@master-1 /usr/local/kubernetes/certs/etcd]# cat >>cfssl.sh<<OEF
> #!/bin/bash
> curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o /usr/local/bin/cfssl
> curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o /usr/local/bin/cfssljson
> curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o /usr/local/bin/cfssl-certinfo
> chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson /usr/local/bin/cfssl-certinfo
> OEF
[root@master-1 /usr/local/kubernetes/certs/etcd]# sh cfssl.sh
[root@master-1 /usr/local/kubernetes/certs/etcd]# ls /usr/local/bin/
cfssl  cfssl-certinfo  cfssljson

一共三个文件,然后再写一个脚本,证书的有效期为10年,脚本内容如下撒。

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

cat > ca-csr.json <<EOF
{
    "CN": "etcd CA",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing"
        }
    ]
}
EOF

cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

cat > server-csr.json <<EOF
{
    "CN": "etcd",
    "hosts": [
    "192.168.1.200",
    "192.168.1.201",
    "192.168.1.202"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing"
        }
    ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server

需要改的地方为IP地址,用于EtcdSSL证书,所以写装Etcd服务器的IP就行了,执行一下。

[root@master-1 /usr/local/kubernetes/certs/etcd]# sh etcd-certs.sh
[root@master-1 /usr/local/kubernetes/certs/etcd]# mkdir ../../script
[root@master-1 /usr/local/kubernetes/certs/etcd]# ls *.sh | xargs -i mv {} ../../script/
ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem  server.csr  server-csr.json  server-key.pem  server.pem

会有一个警告,忽略撒,文件就是这些,下面开始部署Etcd

部署Etcd集群

全部服务使用编译安装,也就是二进制包,EtcdGitHub地址:https://github.com/etcd-io/etcd/releases,我使用的版本为3.3.12,先下载解压了,在部署之前要一定要关闭selinuxfirewalld&iptables

[root@master-1 ~]# mkdir -p /usr/local/kubernetes/etcd
[root@master-1 ~]# cd /usr/local/kubernetes/etcd
[root@master-1 /usr/local/kubernetes/etcd]# wget https://github.com/etcd-io/etcd/releases/download/v3.3.12/etcd-v3.3.12-linux-amd64.tar.gz
[root@master-1 /usr/local/kubernetes/etcd]# tar zxf etcd-v3.3.12-linux-amd64.tar.gz 
[root@master-1 /usr/local/kubernetes/etcd]# mkdir {bin,cfg,ssl}
[root@master-1 /usr/local/kubernetes/etcd]# mv etcd-v3.3.12-linux-amd64/etcd* ./bin/
[root@master-1 /usr/local/kubernetes/etcd]# rm -rf etcd-v3.3.12-linux-amd64*
[root@master-1 /usr/local/kubernetes/etcd]# tree .
.
├── bin
│   ├── etcd
│   └── etcdctl
├── cfg
└── ssl

3 directories, 2 files

刚刚复制的两个二进制文件,etcd为启动服务,etcdctl为客户端工具,扔到了bin目录,下面要写要做的事情就是编写etcd配置文件,还有就是编写服务启动文件,以方便使用systemctl管理服务。

编写配置文件和启动文件

这里的话也用一个脚本吧,比较简单,需要传入三个参数,分别是Etcd名字,本机IP,和要做集群的服务器IP,脚本会帮我们自动创建配置文件,还有启动文件,以方便使用systemctl去管理服务,WORK_DIR根据自己情况去改,我的位置是/usr/local/kubernetes/etcd,所以脚本内容如下。

#!/bin/bash

ETCD_NAME=$1
ETCD_IP=$2
ETCD_CLUSTER=$3

WORK_DIR=/usr/local/kubernetes/etcd

cat <<EOF >$WORK_DIR/cfg/etcd
#[Member]
ETCD_NAME="${ETCD_NAME}"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://${ETCD_IP}:2380"
ETCD_LISTEN_CLIENT_URLS="https://${ETCD_IP}:2379"

#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://${ETCD_IP}:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://${ETCD_IP}:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://${ETCD_IP}:2380,${ETCD_CLUSTER}"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF

cat <<EOF >/usr/lib/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=${WORK_DIR}/cfg/etcd
ExecStart=${WORK_DIR}/bin/etcd \
--name=\${ETCD_NAME} \
--data-dir=\${ETCD_DATA_DIR} \
--listen-peer-urls=\${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls=\${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 \
--advertise-client-urls=\${ETCD_ADVERTISE_CLIENT_URLS} \
--initial-advertise-peer-urls=\${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--initial-cluster=\${ETCD_INITIAL_CLUSTER} \
--initial-cluster-token=\${ETCD_INITIAL_CLUSTER_TOKEN} \
--initial-cluster-state=new \
--cert-file=${WORK_DIR}/ssl/server.pem \
--key-file=${WORK_DIR}/ssl/server-key.pem \
--peer-cert-file=${WORK_DIR}/ssl/server.pem \
--peer-key-file=${WORK_DIR}/ssl/server-key.pem \
--trusted-ca-file=${WORK_DIR}/ssl/ca.pem \
--peer-trusted-ca-file=${WORK_DIR}/ssl/ca.pem
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

在执行之前需要把证书文件都移动到指定的文件夹撒,然后执行就可以了,etcd1操作如下

[root@master-1 /usr/local/kubernetes/etcd]# cp ../certs/etcd/ca*pem ./ssl/
[root@master-1 /usr/local/kubernetes/etcd]# cp ../certs/etcd/server*pem ./ssl/
[root@master-1 /usr/local/kubernetes/etcd]# sh etcd.sh etcd01 192.168.1.200 etcd02=https://192.168.1.201:2380,etcd03=https://192.168.1.202:2380

现在只是生成了配置文件和启动文件,暂时不启动。

配置其他节点

etcd复制到其他两个节点

[root@master-1 /usr/local/kubernetes]# ansible etcd -m file -a "path=/usr/local/kubernetes state=directory"
[root@master-1 ~]# ansible etcd -m copy -a "src=/usr/local/kubernetes/etcd dest=/usr/local/kubernetes/ mode=755"
[root@master-1 ~]# ansible etcd -m copy -a "src=/usr/lib/systemd/system/etcd.service dest=/usr/lib/systemd/system"

配置文件这块的话也得改一下,用模块替换有点麻烦,手动改一下直接传过去吧,配置文件如下

[root@master-1 ~/etcd_conf]# cat etcd-etcd02 
#[Member]
ETCD_NAME="etcd02"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.1.201:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.201:2379"

#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.201:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.201:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.1.200:2380,etcd02=https://192.168.1.201:2380,etcd03=https://192.168.1.202:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
[root@master-1 ~/etcd_conf]# cat etcd-etcd03 
#[Member]
ETCD_NAME="etcd03"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.1.202:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.202:2379"

#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.202:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.202:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.1.200:2380,etcd02=https://192.168.1.201:2380,etcd03=https://192.168.1.202:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"

传送配置文件,启动服务

[root@master-1 ~/etcd_conf]# ansible master-2 -m copy -a "src=/root/etcd_conf/etcd-etcd02 dest=/usr/local/kubernetes/etcd/cfg/etcd backup=yes"
[root@master-1 ~/etcd_conf]# ansible node-1 -m copy -a "src=/root/etcd_conf/etcd-etcd03 dest=/usr/local/kubernetes/etcd/cfg/etcd backup=yes"
[root@master-1 ~/etcd_conf]# ansible etcd -m systemd -a "daemon_reload=yes state=started name=etcd.service enabled=yes"
[root@master-1 ~/etcd_conf]# systemctl daemon-reload 
[root@master-1 ~/etcd_conf]# systemctl start etcd.service 
[root@master-1 ~/etcd_conf]# systemctl status etcd.service 

正常启动了,下面看一下集群的状态

查看集群状态

需要指定证书才可以查到正确的状态,要么直接不可用,所以查看状态的命令如下。

[root@master-1 /usr/local/kubernetes/etcd/bin]# ./etcdctl --ca-file=/usr/local/kubernetes/etcd/ssl/ca.pem --cert-file=/usr/local/kubernetes/etcd/ssl/server.pem --key-file=/usr/local/kubernetes/etcd/ssl/server-key.pem --endpoints=https://192.168.1.200:2379,https://192.168.1.201:2379,https://192.168.1.202:2379 cluster-health

没问题,正常状态,这个比较简单,只要确认证书没问题,配置文件正确就可以了。如果出现错误去查logs撒,日志位置/var/log/messages,这个暂时就过了,关于安装docker-ce这块我就不多BB了,node节点都需要安装,下一步部署Flannel网络

Flannel网络部署阶段

Flannel也属于是Overlay Network,覆盖网络的一种,也是讲源数据包封装在另一种网络包里面进行路由转发和通信,目前支持UDP、VXLAN、AWS VPC和GCE路由等数据转发方式,之前swarm自带overlay网络,现在不行了撒,得手动创建了,Flannel会通过etcd存储一个路由表,以实现跨主机通讯,下面部署一下。

写入网段到etcd

[root@master-1 ~]#  etcdctl --ca-file=/usr/local/kubernetes/etcd/ssl/ca.pem --cert-file=/usr/local/kubernetes/etcd/ssl/server.pem --key-file=/usr/local/kubernetes/etcd/ssl/server-key.pem --endpoints="https://192.168.1.200:2379,https://192.168.1.201:2379,https://192.168.1.202:2379" set /coreos.com/network/config '{"Network":"12.13.0.0/16","Backend":{"Type":"vxlan"}}'
{"Network":"12.13.0.0/16","Backend":{"Type":"vxlan"}}
[root@master-1 ~]# etcdctl --ca-file=/usr/local/kubernetes/etcd/ssl/ca.pem --cert-file=/usr/local/kubernetes/etcd/ssl/server.pem --key-file=/usr/local/kubernetes/etcd/ssl/server-key.pem --endpoints=https://192.168.1.200:2379,https://192.168.1.201:2379,https://192.168.1.202:2379 get /coreos.com/network/config
{"Network":"12.13.0.0/16","Backend":{"Type":"vxlan"}}
[root@master-2 ~]# etcdctl --ca-file=/usr/local/kubernetes/etcd/ssl/ca.pem --cert-file=/usr/local/kubernetes/etcd/ssl/server.pem --key-file=/usr/local/kubernetes/etcd/ssl/server-key.pem --endpoints=https://192.168.1.200:2379,https://192.168.1.201:2379,https://192.168.1.202:2379 get /coreos.com/network/config
{"Network":"12.13.0.0/16","Backend":{"Type":"vxlan"}}

第一条命令是创建网络,第二条是查询网络,在别的节点也能查到,没啥问题。

下载Flannel

在官方下载吧,下载地址:https://github.com/coreos/flannel/releases,目前最新版本为0.11.0,所以我用这个撒,直接在服务器上下载,在node节点操作撒

[root@master-1 ~]# ansible node -m get_url -a "url=https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz dest=/usr/local/src"

下载完成之后创建文件夹,将文件解压到bin目录。

[root@master-1 ~]# ansible node -m file -a "path=/usr/local/kubernetes/bin state=directory"
[root@master-1 ~]# ansible node -m file -a "path=/usr/local/kubernetes/cfg state=directory"
[root@master-1 ~]# ansible node -m unarchive -a "src=/usr/local/src/flannel-v0.11.0-linux-amd64.tar.gz dest=/usr/local/kubernetes/bin copy=no"

会用到刚刚生成的证书,所以也需要把证书拷贝过去。

[root@master-1 ~]# ansible node -m copy -a "src=/usr/local/kubernetes/etcd/ssl dest=/usr/local/kubernetes/etcd"

下面就需要编写flanneld 配置文件了。

编写配置文件及启动文件

配置文件内容如下,不要照搬,etcd集群地址和证书位置按自己的去写撒。

[root@master-1 ~/k8S/config/flannel]# cat flanneld

FLANNEL_OPTIONS="--etcd-endpoints=https://192.168.1.200:2379,https://192.168.1.201:2379,https://192.168.1.202:2379 -etcd-cafile=/usr/local/kubernetes/etcd/ssl/ca.pem -etcd-certfile=/usr/local/kubernetes/etcd/ssl/server.pem -etcd-keyfile=/usr/local/kubernetes/etcd/ssl/server-key.pem"

然后是flannel的启动文件,也不要照搬,配置文件位置两个执行文件的位置按自己的写,内容如下

[root@master-1 ~/k8S/config/flannel]# cat flanneld.service 
[Unit]
Description=Flanneld overlay address etcd agent
After=network-online.target network.target
Before=docker.service

[Service]
Type=notify
EnvironmentFile=/usr/local/kubernetes/cfg/flanneld
ExecStart=/usr/local/kubernetes/bin/flanneld --ip-masq $FLANNEL_OPTIONS
ExecStartPost=/usr/local/kubernetes/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/subnet.env
Restart=on-failure

[Install]
WantedBy=multi-user.target

启动之后会在/run/flannel/subnet.env生成一个子网,下面开始启动服务。

启动服务

要把刚刚写好的两个配置文件传到node节点,操作如下。

[root@master-1 ~/k8S/config/flannel]# ansible node -m copy -a "src=./flanneld dest=/usr/local/kubernetes/cfg/"
[root@master-1 ~/k8S/config/flannel]# ansible node -m copy -a "src=./flanneld.service dest=/usr/lib/systemd/system/"

已经传好了,阔以启动服务了撒。

[root@master-1 ~/k8S/config/flannel]# ansible node -m systemd -a "daemon_reload=yes state=started name=flanneld.service enabled=yes"

确认一下文件是否生成了,如果生成了就说明启动成功了,看一下。

[root@master-1 ~/k8S/config/flannel]# ansible node -m shell -a "cat /run/flannel/subnet.env"

文件有了,还会有一个名为flannel.1的网卡

[root@master-1 ~]# ansible node -m shell -a "ifconfig flannel.1"

再看一眼路由表,

[root@master-1 ~]# ansible node -m shell -a "route"

没问题,下面就指定docker使用这个网络

docker 融合 flannel网络

需要指定一下docker启动时使用的子网,也就是使用flannel网络,需要去改一下docker的启动文件,加点东西即可,如下。

[root@master-1 ~]# vim /usr/lib/systemd/system/docker.service
EnvironmentFile=/run/flannel/subnet.env   #引入变量
ExecStart=/usr/bin/dockerd -H fd:// $DOCKER_NETWORK_OPTIONS #使用变量

我是在master节点改好了,所以直接传到node节点然后重启docker就可以了,其实master节点不用装docker,而且也用不到,传一下,重启一下服务。

[root@master-1 ~]# ansible node -m copy -a "src=/usr/lib/systemd/system/docker.service dest=/usr/lib/systemd/system/"
[root@master-1 ~]# ansible node -m systemd -a "daemon_reload=yes name=docker state=restarted"

检索一下dockerd,看看生效了没

[root@master-1 ~]# ansible node -m shell -a "ps aux | grep dockerd"

已经应用到flannel的子网了,最后测试,在不同主机分别启动一个容器,互相ping一下就可以了,登录到node{1..2}测试。

在宿主机node1节点ping一下node2的网关,如果能通,基本就没问题了

[root@node-1 ~]# ifconfig flannel.1
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 12.13.47.0  netmask 255.255.255.255  broadcast 0.0.0.0
[root@node-2 ~]$ ifconfig flannel.1
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 12.13.59.0  netmask 255.255.255.255  broadcast 0.0.0.0
[root@node-1 ~]# ping -c 2 12.13.59.0
PING 12.13.59.0 (12.13.59.0) 56(84) bytes of data.
64 bytes from 12.13.59.0: icmp_seq=1 ttl=64 time=0.421 ms
64 bytes from 12.13.59.0: icmp_seq=2 ttl=64 time=0.288 ms

--- 12.13.59.0 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.288/0.354/0.421/0.069 ms
[root@node-2 ~]$ ping -c 3 12.13.47.0
PING 12.13.47.0 (12.13.47.0) 56(84) bytes of data.
64 bytes from 12.13.47.0: icmp_seq=1 ttl=64 time=0.293 ms
64 bytes from 12.13.47.0: icmp_seq=2 ttl=64 time=0.321 ms
64 bytes from 12.13.47.0: icmp_seq=3 ttl=64 time=0.400 ms

--- 12.13.47.0 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.293/0.338/0.400/0.045 ms

没问题,然后两个节点各启动一个容器,互相ping一下试试

[root@node-1 ~]# docker run -it busybox
/ # ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:0C:0D:2F:02  
          inet addr:12.13.47.2  Bcast:12.13.47.255  Mask:255.255.255.0
[root@node-2 ~]$ docker run -it busybox
/ # ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:0C:0D:3B:02  
          inet addr:12.13.59.2  Bcast:12.13.59.255  Mask:255.255.255.0
/ # ping -c 3 12.13.47.2
PING 12.13.47.2 (12.13.47.2): 56 data bytes
64 bytes from 12.13.47.2: seq=0 ttl=62 time=0.733 ms
64 bytes from 12.13.47.2: seq=1 ttl=62 time=0.596 ms
64 bytes from 12.13.47.2: seq=2 ttl=62 time=0.517 ms

--- 12.13.47.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.517/0.615/0.733 ms
/ # 

没问题,可以通,到此,node1就不ping node2了,绝对能通,到此,flannel网络部署完成,现在etcd数据库集群、flannel网络、docker都已经部署完成,下一步该部署Master组件了。

单Master集群-部署Master-1组件

Master有三个组件,分别为kube-apiserver、kube-controller-manager、kube-schedulerkube-apiserver需要证书,现在还需要自签一个ssl证书,开撸,在master-1操作,以下操作为单Master操作,非Master集群,现在只有etcd数据库是集群,暂时还没有涉及到master-2,单机结束后会涉及到。

自签SSL证书

[root@master-1 ~]# cd /usr/local/kubernetes/
[root@master-1 /usr/local/kubernetes]# mkdir -p k8s

贴一个脚本,改改直接执行就好,内容如下。

[root@master-1 /usr/local/kubernetes/k8s]# cat k8s-cert.sh 
cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

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

cfssl gencert -initca ca-csr.json | cfssljson -bare ca -


cat > server-csr.json <<EOF
{
    "CN": "kubernetes",
    "hosts": [
      "10.0.0.1",
      "127.0.0.1",
      "192.168.1.200",
      "192.168.1.201",
      "192.168.1.205",
      "192.168.1.206",
      "192.168.1.207",
      "kubernetes",
      "kubernetes.default",
      "kubernetes.default.svc",
      "kubernetes.default.svc.cluster",
      "kubernetes.default.svc.cluster.local"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server


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

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin


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

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy

你需要改的位置只有一处,那就是server-csr.json下的IP10.0.0.1&127.0.0.1不要动,剩下的IP不知道是哪些节点可以到上面看一下我的环境规划就知道了,10网段为api-server在集群内部的地址,不要动,下面的IPmaster ip和负载均衡器IP,包括VIPmaster的地址必须写,加了负载均衡器的地址,以免出现问题,node节点不用,下面开始执行吧。

[root@master-1 /usr/local/kubernetes/k8s]# sh k8s-cert.sh
[root@master-1 /usr/local/kubernetes/k8s]# ls
admin.csr       admin-key.pem  ca-config.json  ca-csr.json  ca.pem       kube-proxy.csr       kube-proxy-key.pem  server.csr       server-key.pem
admin-csr.json  admin.pem      ca.csr          ca-key.pem   k8s-cert.sh  kube-proxy-csr.json  kube-proxy.pem      server-csr.json  server.pem

忽略警告,证书就是这些,现在证书生成完了,可以去下载kubernetes二进制包了。

下载kubernetes

官方地址:https://github.com/kubernetes/kubernetes/releases

目前最新稳定版本为1.12.6,所以我直接在master-01上下载了,我下载的是server的二进制包,包含所有的组件。

[root@master-1 /usr/local/kubernetes/soft]# wget https://dl.k8s.io/v1.12.6/kubernetes-server-linux-amd64.tar.gz

这个包有点大,而且下载也慢,等吧,先把目录创建了,我安装目录如下,顺便把包解压了

[root@master-1 /usr/local/kubernetes/soft]# mkdir /usr/local/kubernetes/{bin,cfg,ssl} -p
[root@master-1 /usr/local/kubernetes/soft]# tar zxf kubernetes-server-linux-amd64.tar.gz
[root@master-1 /usr/local/kubernetes/soft]# cd kubernetes/
[root@master-1 /usr/local/kubernetes/soft/kubernetes]# ls
addons  kubernetes-src.tar.gz  LICENSES  server

会看到有两个目录,addons目录为插件目录,server目录为存放的二进制包,复制一下文件到指定位置。

[root@master-1 /usr/local/kubernetes/soft/kubernetes/server/bin]# cp kube-apiserver kubectl kube-controller-manager kube-scheduler /usr/local/kubernetes/bin/

复制完了,开始部署apiserver

部署kube-apiserver

二进制包拷贝完了,下一步要做的就是编写配置文件和启动文件,启动服务,一步一步来,先整理一下证书,暂时存放的位置为/usr/local/kubernetes/k8s,现在复制到ssl目录

[root@master-1 /usr/local/kubernetes/k8s]# ls | xargs -i cp {} ../ssl/

然后一个脚本用来部署kube-apiserver,内容如下。

[root@master-1 /usr/local/kubernetes/script]# cat kube-apiserver.sh 
#!/bin/bash

MASTER_ADDRESS=$1
ETCD_SERVERS=$2

cat <<EOF >/usr/local/kubernetes/cfg/kube-apiserver

KUBE_APISERVER_OPTS="--logtostderr=true \\
--v=4 \\
--etcd-servers=${ETCD_SERVERS} \\
--bind-address=${MASTER_ADDRESS} \\
--secure-port=6443 \\
--advertise-address=${MASTER_ADDRESS} \\
--allow-privileged=true \\
--service-cluster-ip-range=10.0.0.0/24 \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \\
--authorization-mode=RBAC,Node \\
--kubelet-https=true \\
--enable-bootstrap-token-auth \\
--token-auth-file=/usr/local/kubernetes/cfg/token.csv \\
--service-node-port-range=30000-50000 \\
--tls-cert-file=/usr/local/kubernetes/ssl/server.pem  \\
--tls-private-key-file=/usr/local/kubernetes/ssl/server-key.pem \\
--client-ca-file=/usr/local/kubernetes/ssl/ca.pem \\
--service-account-key-file=/usr/local/kubernetes/ssl/ca-key.pem \\
--etcd-cafile=/usr/local/kubernetes/etcd/ssl/ca.pem \\
--etcd-certfile=/usr/local/kubernetes/etcd/ssl/server.pem \\
--etcd-keyfile=/usr/local/kubernetes/etcd/ssl/server-key.pem"

EOF

cat <<EOF >/usr/lib/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=-/usr/local/kubernetes/cfg/kube-apiserver
ExecStart=/usr/local/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable kube-apiserver
systemctl restart kube-apiserver

传入当前主机IPetcd集群地址,就可以了,还需要生成一下token.csv文件,上面允许使用token认证了,并且制定了认证文件为token.csv,现在还没有,所以先生成一下撒。

[root@master-1 ~]# echo ',kubelet-bootstrap,10001,\"system:kubelet-bootstrap\"' | xargs echo `head -c 16 /dev/urandom | od -An -t x ` | tr -d ' ' > /usr/local/kubernetes/cfg/token.csv 
[root@master-1 ~]# cat /usr/local/kubernetes/cfg/token.csv 
994a53f93efe937f81122d477792e271,kubelet-bootstrap,10001,"system:kubelet-bootstrap"

正常的文件第一段为token,第二段为用户,名为kubelet-bootstrap,第三段为UID,第四段为系统组,主要是部署kubelet去用的,现在可以执行脚本了。

[root@master-1 /usr/local/kubernetes/script]# sh kube-apiserver.sh 192.168.1.200 https://192.168.1.200:2379,https://192.168.1.201:2379,https://192.168.1.202:2379
Created symlink from /etc/systemd/system/multi-user.target.wants/kube-apiserver.service to /usr/lib/systemd/system/kube-apiserver.service.
[root@master-1 /usr/local/kubernetes/script]# systemctl status kube-apiserver.service 

OK,没问题,正常启动了,下面部署kube-controller-manager

部署kube-controller-manager

还是老样子,编写配置文件,编写启动文件,启动服务,上脚本,脚本内容如下。

[root@master-1 /usr/local/kubernetes/script]# cat controller-manager.sh 
#!/bin/bash

MASTER_ADDRESS=$1

cat <<EOF >/usr/local/kubernetes/cfg/kube-controller-manager


KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=true \\
--v=4 \\
--master=${MASTER_ADDRESS}:8080 \\
--leader-elect=true \\
--address=127.0.0.1 \\
--service-cluster-ip-range=10.0.0.0/24 \\
--cluster-name=kubernetes \\
--cluster-signing-cert-file=/usr/local/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/usr/local/kubernetes/ssl/ca-key.pem  \\
--root-ca-file=/usr/local/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/usr/local/kubernetes/ssl/ca-key.pem \\
--experimental-cluster-signing-duration=87600h0m0s"

EOF

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

[Service]
EnvironmentFile=-/usr/local/kubernetes/cfg/kube-controller-manager
ExecStart=/usr/local/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable kube-controller-manager
systemctl restart kube-controller-manager

传一个参数,需要指定一下master的地址,这里写本机就好了

[root@master-1 /usr/local/kubernetes/script]# sh controller-manager.sh 127.0.0.1
Created symlink from /etc/systemd/system/multi-user.target.wants/kube-controller-manager.service to /usr/lib/systemd/system/kube-controller-manager.service.
[root@master-1 /usr/local/kubernetes/script]# systemctl status kube-controller-manager.service

没问题,正常启动了,接下来启动scheduler

部署scheduler

编写配置文件,编写启动文件,启动服务,上脚本,脚本内容如下。

[root@master-1 /usr/local/kubernetes/script]# cat scheduler.sh
#!/bin/bash

MASTER_ADDRESS=$1

cat <<EOF >/usr/local/kubernetes/cfg/kube-scheduler

KUBE_SCHEDULER_OPTS="--logtostderr=true \\
--v=4 \\
--master=${MASTER_ADDRESS}:8080 \\
--leader-elect"

EOF

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

[Service]
EnvironmentFile=-/usr/local/kubernetes/cfg/kube-scheduler
ExecStart=/usr/local/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable kube-scheduler
systemctl restart kube-scheduler

传入一个参数,传入master地址,也就是本机,所以开始执行吧。

[root@master-1 /usr/local/kubernetes/script]# sh scheduler.sh 127.0.0.1
[root@master-1 /usr/local/kubernetes/script]# systemctl status kube-scheduler.service

正常启动了,最后测一下

测试Master组件

master的组件全部安装完成而且启动了,最后测一下,是否真的工作正常,用一条命令检测一下就好。

[root@master-1 ~]# export PATH=$PATH:/usr/local/kubernetes/bin/
[root@master-1 ~]# kubectl get cs
NAME                 STATUS    MESSAGE             ERROR
controller-manager   Healthy   ok                  
scheduler            Healthy   ok                  
etcd-2               Healthy   {"health":"true"}   
etcd-0               Healthy   {"health":"true"}   
etcd-1               Healthy   {"health":"true"}   

没问题,大概就这样,工作正常,下面该部署NODE组件了。

部署NODE组件

部署NODE组件,大概是分为三步,第一是将kubelet-bootstrap用户绑定到系统集群角色,第二创建kubeconfig文件,第三部署kubelet、kube-proxy组件,先来看第一个,刚刚创建了一个token,也就是这个撒。

[root@master-1 ~]# cat /usr/local/kubernetes/cfg/token.csv 
994a53f93efe937f81122d477792e271,kubelet-bootstrap,10001,"system:kubelet-bootstrap"

kubelet启动过程如下,现在kubelet配置文件还没有,一会要生成,读取配置文件后回去连接apiserver,接下来就是验证了,token&证书有一个验证失败了就直接启动失败,验证过了颁发证书启动成功了。

先把组件传到NODE节点吧。

[root@master-1 ~]# ansible node -m copy -a "src=/usr/local/kubernetes/soft/kubernetes/server/bin/kubelet dest=/usr/local/kubernetes/bin/ mode=0755"
[root@master-1 ~]# ansible node -m copy -a "src=/usr/local/kubernetes/soft/kubernetes/server/bin/kube-proxy dest=/usr/local/kubernetes/bin/ mode=0755"

下面开始启动kubelet

启动kubelet

直接上脚本,内容如下。

BOOTSTRAP_TOKEN=994a53f93efe937f81122d477792e271

cat > token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF


APISERVER=$1
SSL_DIR=$2

export KUBE_APISERVER="https://$APISERVER:6443"

kubectl config set-cluster kubernetes \
  --certificate-authority=$SSL_DIR/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=bootstrap.kubeconfig

kubectl config set-credentials kubelet-bootstrap \
  --token=${BOOTSTRAP_TOKEN} \
  --kubeconfig=bootstrap.kubeconfig

kubectl config set-context default \
  --cluster=kubernetes \
  --user=kubelet-bootstrap \
  --kubeconfig=bootstrap.kubeconfig

kubectl config use-context default --kubeconfig=bootstrap.kubeconfig


kubectl config set-cluster kubernetes \
  --certificate-authority=$SSL_DIR/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-proxy.kubeconfig

kubectl config set-credentials kube-proxy \
  --client-certificate=$SSL_DIR/kube-proxy.pem \
  --client-key=$SSL_DIR/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

需要改一个变量,自己的tonken是什么就写什么,传入两个参数,一个是api-server的地址,一个是证书的位置,在Master节点创建配置文件吧,生成好之后直接传到NODE节点,开始执行吧。

[root@master-1 /usr/local/kubernetes/kubeconfig]# sh kubeconfig.sh 192.168.1.200 /usr/local/kubernetes/ssl/
[root@master-1 /usr/local/kubernetes/kubeconfig]# ls
bootstrap.kubeconfig  kubeconfig.sh  kube-proxy.kubeconfig  token.csv

生成好之后,就可以传到Node节点了,传两个就够了。

[root@master-1 /usr/local/kubernetes/kubeconfig]# ansible node -m copy -a "src=./bootstrap.kubeconfig dest=/usr/local/kubernetes/cfg/"
[root@master-1 /usr/local/kubernetes/kubeconfig]# ansible node -m copy -a "src=./kube-proxy.kubeconfig dest=/usr/local/kubernetes/cfg/"

继续上脚本,用来部署kubelet的,内容如下。

#!/bin/bash
ifconfig || yum -y install net-tools 

NETWORK=`route -n | awk NR==3p  | awk -F '[:. ]+' '{print $5"."$6}'`
NODE_ADDRESS=`ifconfig -a | awk '{print $2}'|tr -d "addr:" | grep "$NETWORK"`
DNS_SERVER_IP=${2:-"10.0.0.2"}

cat <<EOF >/usr/local/kubernetes/cfg/kubelet

KUBELET_OPTS="--logtostderr=true \\
--v=4 \\
--address=${NODE_ADDRESS} \\
--hostname-override=${HOSTNAME} \\
--kubeconfig=/usr/local/kubernetes/cfg/kubelet.kubeconfig \\
--experimental-bootstrap-kubeconfig=/usr/local/kubernetes/cfg/bootstrap.kubeconfig \\
--config=/usr/local/kubernetes/cfg/kubelet.config \\
--cert-dir=/usr/local/kubernetes/ssl \\
--pod-infra-container-image=swr.cn-north-1.myhuaweicloud.com/rj-bai/pause-amd64:3.1"

EOF

cat <<EOF >/usr/local/kubernetes/cfg/kubelet.config

kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: ${NODE_ADDRESS}
port: 10250
cgroupDriver: cgroupfs
clusterDNS:
- ${DNS_SERVER_IP} 
clusterDomain: cluster.local.
failSwapOn: false
authentication:
  anonymous:
    enabled: true

EOF

cat <<EOF >/usr/lib/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
After=docker.service
Requires=docker.service

[Service]
EnvironmentFile=/usr/local/kubernetes/cfg/kubelet
ExecStart=/usr/local/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
KillMode=process

[Install]
WantedBy=multi-user.target
EOF

还是做了那些事情,你需要改的证书位置,节点IP是自动获取的,可能不适合你,酌情更改吧,然后设置了一个DNS服务器的地址,指定的是10.0.0.2,以后需要装DNS插件,所以定的是这个,节点在集群显示的名称我用的主机名,如果使用主机名请在master节点添加对应节点的host解析,不推荐用主机名,建议使用该节点IP,否则后期你会发现N多问题,但是我用IP后期看着会很晕,所以还是用主机名了,大概就这样,这个脚本直接在Node节点执行就行了。

[root@master-1 /usr/local/kubernetes/script]# ansible node -m script -a "./kubelet.sh"

然后需要在集群中创建kubelet-bootstrap用户,否则kubelet是无法启动的,下面来创建一下。

[root@master-1 /usr/local/kubernetes/script]# kubectl create clusterrolebinding kubelet-bootstrap \
>   --clusterrole=system:node-bootstrapper \
>   --user=kubelet-bootstrap
clusterrolebinding.rbac.authorization.k8s.io/kubelet-bootstrap created

创建完了,现在可以启动了。

[root@master-1 /usr/local/kubernetes/script]# ansible node -m systemd -a "daemon_reload=yes state=restarted name=kubelet.service enabled=yes"

然后再启动一下kube-proxy

启动kube-proxy

继续上脚本,内容如下,还是获取IP方式和证书位置自行调整。

#!/bin/bash

NETWORK=`route -n | awk NR==3p  | awk -F '[:. ]+' '{print $5"."$6}'`
NODE_ADDRESS=`ifconfig -a | awk '{print $2}'|tr -d "addr:" | grep "$NETWORK"`

cat <<EOF >//usr/local/kubernetes/cfg/kube-proxy

KUBE_PROXY_OPTS="--logtostderr=true \\
--v=4 \\
--hostname-override=${NODE_ADDRESS} \\
--cluster-cidr=10.0.0.0/24 \\
--proxy-mode=ipvs \\
--masquerade-all=true \\
--kubeconfig=//usr/local/kubernetes/cfg/kube-proxy.kubeconfig"

EOF

cat <<EOF >/usr/lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Proxy
After=network.target

[Service]
EnvironmentFile=-//usr/local/kubernetes/cfg/kube-proxy
ExecStart=//usr/local/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

需要装一个ipset软件包,我直接执行了,执行完启动服务。

[root@master-1 /usr/local/kubernetes/script]# ansible node -m yum -a "name=ipset state=installed"
[root@master-1 /usr/local/kubernetes/script]# ansible node -m script -a "./kube-proxy.sh"
[root@master-1 /usr/local/kubernetes/script]# ansible node -m systemd -a "daemon_reload=yes state=started name=kube-proxy.service enabled=yes"

全部正常启动了,最后确认一下组件是否发送签名请求,有的话给他办法证书且加入到集群,接下来在master节点操作。

最终测试

查看Master节点是否接收到Node节点颁发证书的请求,命令如下。

[root@master-1 ~]# kubectl get csr
NAME                                                   AGE   REQUESTOR           CONDITION
node-csr-0VP6ZmWqRAPUakygyZpe4Mg1KpnR4wW4dRifE76GdZ4   22m   kubelet-bootstrap   Pending
node-csr-8La9nCMfle3sbHQcRwQCvfT87LjNXzOPyyLBFPLdg2w   22m   kubelet-bootstrap   Pending
node-csr-SY1NrfhG34WyNkxoRCsoMJXHfFqQ3D-tLrZCM9ulL4g   22m   kubelet-bootstrap   Pending

可以看到一共是三个,我就三个Node节点,所以没问题,现在手动允许颁发证书,就可以加入到节点了,操作如下。

[root@master-1 ~]# for i in `kubectl get csr | grep -v NAME | awk {'print $1'}`
>  do 
>   kubectl certificate approve $i 
> done
[root@master-1 ~]# kubectl get node

加进来了,到此Kubernetes单节点的Master已经部署完成,也就是这个图。

最后再看一下Master组价的状态和全部节点,全部工作正常,如果有不正常的自查吧,下面启一个服务试试。

集群最终测试

集群是已经搭建出来了,但特么是能不能用还是回事呢,所以,启服务测试,下面创建一个podspods是由一个或多个容器组成,是K8S最小部署单元,下面用命令行创建一个。

[root@master-1 ~]# kubectl run nginx --image=nginx
kubectl run --generator=deployment/apps.v1beta1 is DEPRECATED and will be removed in a future version. Use kubectl create instead.
deployment.apps/nginx created
[root@master-1 ~]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
nginx-dbddb74b8-qq9vj   1/1     Running   0          39s

这样就创建好了,看一下所有运行的资源。

[root@master-1 ~]# kubectl get all

可以看到是由三个在运行,会发现有一个deployment,他是用来管理replicasetreplicaset来管理PODS,都是运行状态,现在把nginx端口暴露出去,操作如下。

[root@master-1 ~]# kubectl expose deployment nginx --port=80 --target-port=80 --type=NodePort
service/nginx exposed
[root@master-1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP        19h
nginx        NodePort    10.0.0.199   <none>        80:30194/TCP   12s

创建好了,一个内部的IP,现在在node节点试着访问以下。

[root@master-1 ~]# ansible node -m get_url -a "url=http://10.0.0.199 dest=/tmp"

没问题,可以访问到,刚刚访问的是内部地址,一共是暴露两个端口,80是对内的,可以访问到,还有一个是30194,这个是对外的,试一下,循环访问Node节点的30194端口。

[root@master-1 ~]# for i in `echo 192.168.1.{202..204}:30194`
> do 
>  curl -I $i
> done

大概是这样,没问题,集群正常,看一下nginx的访问日志。

[root@master-1 ~]# kubectl logs nginx-dbddb74b8-qq9vj
Error from server (Forbidden): Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=proxy) ( pods/log nginx-dbddb74b8-qq9vj)

没权限撒,因为是匿名用户,没有权限去访问,现在将system:anonymous用户绑定到系统角色,让他有权限,命令如下。

[root@master-1 ~]# kubectl create clusterrolebinding cluster-system-anoymous --clusterrole=cluster-admin --user=system:anonymous
[root@master-1 ~]# kubectl logs nginx-dbddb74b8-qq9vj

没问题了撒,集群正常,下面部署一下WEB UI

部署WEB UI

也就是Kubernetes Dashboard,文件存放位置如下。

[root@master-1 /usr/local/kubernetes/soft/kubernetes]# pwd
/usr/local/kubernetes/soft/kubernetes
[root@master-1 /usr/local/kubernetes/soft/kubernetes]# tar zxf kubernetes-src.tar.gz 
[root@master-1 /usr/local/kubernetes/soft/kubernetes]# cd cluster/addons/dashboard/
[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# ls
dashboard-configmap.yaml  dashboard-controller.yaml  dashboard-rbac.yaml  dashboard-secret.yaml  dashboard-service.yaml  MAINTAINERS.md  OWNERS  README.md

GitHub地址,下面开始创建一下。

[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# kubectl create -f dashboard-configmap.yaml 
configmap/kubernetes-dashboard-settings created
[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# kubectl create -f dashboard-rbac.yaml 
role.rbac.authorization.k8s.io/kubernetes-dashboard-minimal created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard-minimal created
[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# kubectl create -f dashboard-secret.yaml 
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-key-holder created

现在需要一个名为kubernetes-dashboard-amd64的镜像,默认地址是k8s.gcr.io/kubernetes-dashboard-amd64,但是这个镜像在国内是无法下载的,感谢快活提供境外服务器,现在最新版本是v1.10.1,所以我用的也是这个版本,然后将镜像传到了华为云,所以直接用就好,修改配置文件,改完之后直接启动。

[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# vim dashboard-controller.yaml
        image: swr.cn-north-1.myhuaweicloud.com/rj-bai/kubernetes-dashboard-amd64:v1.10.1
[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# kubectl create -f dashboard-controller.yaml 
serviceaccount/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# kubectl get pods -n kube-system
NAME                                    READY   STATUS    RESTARTS   AGE
kubernetes-dashboard-6698c5f4c6-mq2qx   1/1     Running   0          30s

阔以看到启动了,下一步创建Service,修改文件。

[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# vim dashboard-service.yaml
spec:
  type: NodePort
[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# kubectl create -f dashboard-service.yaml 
service/kubernetes-dashboard created
[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# kubectl get svc -n kube-system
NAME                   TYPE       CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kubernetes-dashboard   NodePort   10.0.0.239   <none>        443:42422/TCP   39s

创建好了,现在去访问以下,Node节点加42422,需要https,自签根证书,不受信任继续访问,正常的话会看到这个。

我们使用令牌登陆,要生成一个。

[root@master-1 ~]# cat K8s-admin.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard-admin
  namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: dashboard-admin
subjects:
  - kind: ServiceAccount
    name: dashboard-admin
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
[root@master-1 ~]# kubectl create -f K8s-admin.yaml 
serviceaccount/dashboard-admin created
clusterrolebinding.rbac.authorization.k8s.io/dashboard-admin created

创建完了,查看以下token

[root@master-1 ~]# kubectl get secret -n kube-system
dashboard-admin-token-5ctgg        kubernetes.io/service-account-token   3      73s
[root@master-1 ~]# kubectl describe secret dashboard-admin-token-5ctgg -n kube-system

最下面那一串就是了,复制一下,使用token登陆就可以了,复制的时候一定要注意,这是一行,不要有任何换行,验证登陆之后就阔以看到概况了。

查看外部端口

[root@master-1 ~]# kubectl get svc -n kube-system
NAME                   TYPE       CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kubernetes-dashboard   NodePort   10.0.0.239   <none>        443:42422/TCP   102m

自己点点看看吧,功能的话还算比较单一,调试时候用用就行了,远程执行命令和看日志都看不了,因为我Node节点都是以主机名去立连接的,自己留的一个坑,如果你想换成IP,也就是给节点改名,请修改kubelet配置文件--hostname-override值,修改完之后删除掉/usr/local/kubernetes/ssl/kubelet*,重启kubelet,去master将新的颁发请求通过一下,之前的通过kubelet delete node <节点名>删掉就好,之后会有集群监控系统,不必太在意这个,过,下面开始部署多Master集群。

多Master集群

Master架构如下。

生产使用的话最好是保证Master是高可用的,对于单Master相对复杂,Etcd已经是高可用了,master如果挂了就无法管理集群了,有些功能也用不了了,所以要部署多Mastermaster高可用主要在于api-server,其他的两个一个调度一个控制器本身就是高可用的,api-server是以http服务对外提供服务的,所以现在要有一个负载均衡器,他负责多个api-server的负载均衡,其他组件连接apisrver直接连vip,现在再启动一个Master,下面开始搞吧。

复制master1文件到master2

直接把/usr/local/kubernetes/{bin,cfg,ssl}目录复制到master-2,还是启动文件,直接用scp了。

[root@master-1 ~]# scp -r /usr/local/kubernetes/{bin,cfg,ssl} master-2:/usr/local/kubernetes/
[root@master-1 ~]# scp /usr/lib/systemd/system/{kube-apiserver,kube-controller-manager,kube-scheduler}.service master-2:/usr/lib/systemd/system

然后修改配置文件

修改配置文件

修改apiserver配置文件,除了这个就没啥可改的了。

[root@master-2 /usr/local/kubernetes]# cd /usr/local/kubernetes/cfg/
[root@master-2 /usr/local/kubernetes/cfg]# vim kube-apiserver
--bind-address=192.168.1.201 \
--advertise-address=192.168.1.201 \

启动服务

[root@master-2 /usr/local/kubernetes/cfg]# systemctl enable {kube-apiserver,kube-controller-manager,kube-scheduler}.service
[root@master-2 /usr/local/kubernetes/cfg]# systemctl start {kube-apiserver,kube-controller-manager,kube-scheduler}.service
[root@master-2 /usr/local/kubernetes/cfg]# systemctl status {kube-apiserver,kube-controller-manager,kube-scheduler}.service
[root@master-2 /usr/local/kubernetes/cfg]# kubectl get cs
[root@master-2 /usr/local/kubernetes/cfg]# kubectl get nodes
[root@master-2 /usr/local/kubernetes/cfg]# kubectl get pods

master-1都是一样的东西,所以都正常启动了,没问题,也能看到节点和pods,证明了K8S集群中所有数据全部都存到了Etcd中。只要能连接到Etcd集群就能查到数据,再加Master同理,下面开始做负载均衡。

apiserver负载均衡

这里直接上nginx,安装nginx就不用多说了,给两个负载均衡批量安装一下,直接用yum装,说白了下面的操作就是做了一个nginx+keepalived高可用,能看这种文档的相信这东西肯定都做过,下面就大概写一下。

[root@master-1 ~]# cat nginx.repo 
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/x86_64/
gpgcheck=0
enabled=1
[root@master-1 ~]# ansible loadbalancer -m copy -a "src=./nginx.repo dest=/etc/yum.repos.d/"
[root@master-1 ~]# ansible loadbalancer -m yum -a "update_cache=yes name=nginx state=installed"
[root@master-1 ~]# ansible loadbalancer -m systemd -a "state=started name=nginx.service enabled=yes"

我们之前一般用的都是upstream,这个是七层的负载模块,现在要用stream了,这个是四层的,所以我把http模块删掉了,自行编译nginx记得启用steam模块,贴一下我的nginx.conf

[root@master-1 ~]# cat nginx.conf 
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
  use epoll;
  accept_mutex on;
  multi_accept on;
  worker_connections  65535;

}

  stream {
    log_format  main  '$remote_addr - [$time_local] ' '$status ' '$upstream_addr';

    upstream k8s-apiserver {
      server 192.168.1.200:6443;
      server 192.168.1.201:6443;
 }

  server {
    listen 6443;
    proxy_pass k8s-apiserver;

    }

    access_log /var/log/nginx/api-server.log main ;
}

先把配置文件传过去,重启服务。

[root@master-1 ~]# ansible loadbalancer -m copy -a "src=./nginx.conf dest=/etc/nginx/ backup=yes"
[root@master-1 ~]# ansible loadbalancer -m systemd -a "state=restarted name=nginx.service"

现在nginx配置好了,下面做高可用。

高可用

直接上keepalived,架一个VIP,步骤大概是安装keepalived,写配置文件,启动服务,按着环境规划,我用的VIP207,我的操作如下。

[root@master-1 ~]# ansible loadbalancer -m yum -a "name=keepalived state=installed"
[root@master-1 ~/HA]# cat keepalived.conf 
! Configuration File for keepalived 
 
global_defs { 
   notification_email { 
   onlydalin@vip.qq.com
   } 
   notification_email_from Alexandre.Cassen@firewall.loc  
   smtp_server 127.0.0.1 
   smtp_connect_timeout 30 
   router_id NGINX_MASTER 
} 

vrrp_script check_nginx {
    script "/etc/keepalived/nginx_check.sh"
}

vrrp_instance VI_1 { 
    state MASTER 
    interface ens32
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication { 
        auth_type PASS      
        auth_pass 1111 
    }  
    virtual_ipaddress { 
        192.168.1.207/24 
    } 
    track_script {
        check_nginx
    } 
}
[root@master-1 ~/HA]# cat nginx_check.sh 
#!/bin/bash
curl -I -k https://127.0.0.1:6443 > /dev/null 2>&1
if [ "$?" -ne 0 ]
 then
  systemctl stop keepalived.service
fi

备节点改一下优先级就好了,别的不用改,也把脚本传过去,启动服务,测试虚拟IP

[root@master-1 ~/HA]# ansible loadbalancer -m copy -a "src=./nginx_check.sh dest=/etc/keepalived/ mode=0755"
[root@master-1 ~/HA]# ansible loadbalancer-1 -m copy -a "src=./keepalived.conf dest=/etc/keepalived/ backup=yes"
[root@master-1 ~/HA]# sed -i 's#100#90#g' keepalived.conf
[root@master-1 ~/HA]# ansible loadbalancer-2 -m copy -a "src=./keepalived.conf dest=/etc/keepalived/ backup=yes"
[root@master-1 ~/HA]# ansible loadbalancer -m systemd -a "state=started name=keepalived.service enabled=yes"
[root@master-1 ~/HA]# ping 192.168.1.207 -c 2
[root@master-1 ~/HA]# curl -I 192.168.1.207:6443
[root@master-1 ~/HA]# echo $?

大概就这样,没问题,然后接下来就要改kubectl&kube-proxy的配置文件了,需要将apiserver的地址改为VIP即可,也就是1.207,不直接连接Master节点了,一个一个改嫌麻烦,上脚本。

[root@master-1 ~/HA]# cat sed.sh 
#!/bin/bash
find /usr/local/kubernetes/cfg/* | xargs sed -i "s#200:6443#207:6443#g"
[root@master-1 ~/HA]# ansible node -m script -a "./sed.sh"
[root@master-1 ~/HA]# ansible node -m systemd -a "daemon_reload=yes state=restarted name=kubelet.service enabled=yes"
[root@master-1 ~/HA]# ansible node -m systemd -a "daemon_reload=yes state=restarted name=kube-proxy.service enabled=yes"

这样就好了,负载均衡那离应该有请求了,202&203&204是我的节点IP,看一下

没问题,最后看一眼全部的组件和pod

到此,一个高可用的多Master集群就搭建好了,本篇结束。

最后编辑于: 2019 年 05 月 16 日
返回文章列表 文章二维码 打赏
本页链接的二维码
打赏二维码
添加新评论

已有 2 条评论
  1. 狗子写的东西越来越长了#(狂汗)

    1. @Hran#(内伤)