Kubernetes入门:高可用集群搭建
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
节点,类似swarm
的Manager
节点,Master
有三个组件,分别为API Server
、scheduler
、controller-manager
。分别介绍一下。
master组件
kube-apiserver
- Kubernetes API 集群统一入口,各组件协调者,以RESTful API 提供接口服务,所有对象资源的增删改查和监听都交给
APIServer
处理后在提交给Etcd
存储
- Kubernetes API 集群统一入口,各组件协调者,以RESTful API 提供接口服务,所有对象资源的增删改查和监听都交给
kube-controller-manager
- 处理集群中常规后台任务,一个资源对应一个控制器,而Controller Manager 就是负责管理这些控制器的。
kube-scheduler
- 根据调度算法为新创建的
Pod
选择一个Node
节点,可以任意部署,可以部署在同一个节点上,也可以部署在不同的节点上。
- 根据调度算法为新创建的
etcd
- 分布式键值存储系统,用户保存集群状态数据,比如
Pod
、Service
等对象信息
- 分布式键值存储系统,用户保存集群状态数据,比如
Node组件
kubelet
- 是
Master
在Node
节点上的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
集群
环境规划
下面来看看kubernetes
的部署方式,官方这块提供了三种部署方式,分别如下。
minikube
- 是一个工具,他可以在你本地快速运行一个单点的Kubernetes,仅供测试使用
kubeadmin
- 也是一个工具,提供了
kubeadm init
和kubeadm join
,init
用于初始化master
,join
是将node
加入到master
,用于快速部署Kubernetes
集群,目前kubeadm
还处于是测试版本。
- 也是一个工具,提供了
二进制包
- 下载编译好的二进制包,通过二进制包配置好参数启动就可以组成一个
kubernetes
集群了。
- 下载编译好的二进制包,通过二进制包配置好参数启动就可以组成一个
这三种方式在生产用的话最好了二进制包,minikube
肯定不行撒,他是单点的,kubeadm
不是很完善,有问题,目前是测试版本,他自动生成的证书有效期是一年,这个不太好调整,而且他是一个封装好的工具,部署集群简单的几条命令就完成了,他到底都做了什么,每个组件之前的关联性,你是不知道的,所以你后期维护可能会比较麻烦。
下文将使用二进制方式去部署集群,了解一下各个组件都是干啥子的,可能就是麻烦一点,暂时决定使用七台虚拟机,两个Manager节点,三个Node
节点,软件使用最新稳定版,包括系统,软件版本如下。
软件 | 版本 |
---|---|
Linux操作系统 | CentOS7.6_X64 |
Kubernetes | 1.12.6 |
docker-ce | 18.09.2 |
Etcd | 3.3.12 |
Flannel | 0.11 |
节点规划
角色 | IP | 组件 |
---|---|---|
mater-01 | 192.168.1.200 | kube-apiserver kube-controller-manager kuber-scheduler etcd |
mater-02 | 192.168.1.201 | kube-apiserver kube-controller-manager kuber-scheduler etcd |
node-01 | 192.168.1.202 | kunelet kube-proxy docker flannel etcd |
node-02 | 192.168.1.203 | kunelet kube-proxy docker flannel etcd |
node-03 | 192.168.1.204 | kunelet kube-proxy docker flannel |
Load Balancer Master | 192.168.1.205 192.168.1.207 (VIP) | Nginx L4 |
Load Balancer Backup | 192.168.1.206 | Nginx 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
地址,用于Etcd
的SSL
证书,所以写装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
节点操作撒,建议在master
节点也直接部署了,后期这东西肯定要加的。
[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-scheduler
,kube-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
下的IP
,10.0.0.1&127.0.0.1
不要动,剩下的IP
不知道是哪些节点可以到上面看一下我的环境规划就知道了,10
网段为api-server
在集群内部的地址,不要动,下面的IP
为master ip
和负载均衡器IP
,包括VIP
,master
的地址必须写,加了负载均衡器的地址,以免出现问题,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 \\
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \\
--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
传入当前主机IP
和etcd
集群地址,就可以了,还需要生成一下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
节点吧,这里也是建议直接在master
节点也部署node
组件,我下文没有在master
部署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
readOnlyPort: 10255
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
cat <<EOF >//usr/local/kubernetes/cfg/kube-proxy
KUBE_PROXY_OPTS="--logtostderr=true \\
--v=4 \\
--hostname-override=${HOSTNAME} \\
--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
注意hostname-override
参数,要设置的和kubelet
的一致,需要装一个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
组价的状态和全部节点,全部工作正常,如果有不正常的自查吧,下面启一个服务试试。
集群最终测试
集群是已经搭建出来了,但特么是能不能用还是回事呢,所以,启服务测试,下面创建一个pods
,pods
是由一个或多个容器组成,是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
,他是用来管理replicaset
,replicaset
来管理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
,不受信任继续访问,Chrome
暂时打不开,无法继续访问,我用的Firefox
,正常的话会看到这个。
我们使用令牌登陆,要生成一个。
[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
自己点点看看吧,其实还有问题,其一是Chrome
直接无法访问这个页面,提示不是隐私连接后无法继续前往访问,我用的是Firefox
,在页面内仪表盘既不能远程查看pod
日志,又无法远程连接pod
执行命令,查看日志显示这个,现在来解决一下这两个问题。
日志这个应该是仪表盘的pod
无法解析这个地址,在很久之前我因为这个问题将节点删掉重新加入到集群,但是重新加入后节点名称不是主机名,而是节点的IP
,这样就可以正常看到日志,但是后来又换回主机名了,看IP
真的有点懵逼,其实刚开始我以为是我电脑无法解析node
的名字导致无法访问的,但是我加了hosts
之后错误和上面一样。
我刚开始以为是Coredns
的问题,因为提示的是无法解析node
名称,然后开始看coredns
,加参数升级到了最新的15
依旧没什么卵用, 想起我上个月用kubeadm
搭建了一个集群,要不把这个扔到那里试试?说搞就搞,我还加了一个node
进来,直接复制了yaml
文件过去,创建了一下,结果是可以正常看到pod
日志的,而且这个集群的node
名字也都是主机名,不是IP
然后我又开始怀疑是不是版本或是启动参数有问题,然后对比了一下kubeadm
启动的服务和我手动搭建启动的服务有啥子区别,是不是缺啥子参数,仔细看了一下发现kube-apiserver
这里的有点区别,如下。
kubeadmn
二进制安装
就是这个参数我二进制启动的没有。
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
死马当活马医吧,把这条参数了进去,重启一下试试。
[root@master-1 ~]# cat /usr/local/kubernetes/cfg/kube-apiserver | grep -i hostname
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \
[root@master-1 ~]# systemctl daemon-reload
[root@master-1 ~]# systemctl restart kube-apiserver
再打开页面看一下,没问题了,可以正常看到日志了。
这个算是解决了,上面的参数已加入到脚本中,在官网查了一下这条参数,是用于指定Kubelet
连接的首选节点的方法,默认值是Hostname,InternalDNS,InternalIP,ExternalDNS,ExternalIP
,上面的配置就是将InternalDNS&ExternalDNS
方法去掉了,而且暂时是没发现别的服务有异常,莫名其妙,都包含了应该没问题啊,还是说有优先级之类的东西,有时间在细琢磨吧,无法远程看日志的问题解决了,下面解决一下无法远程连接pod
的问题。
接下来就是远程连接pod
执行命令这里,点了执行命令之后会又弹出了一个仪表盘,大概这样。
我刚开始以为是FireFox
的问题,查了半天没找到解决办法,于是这件事情就被搁置下来了,直到昨天,偶然发现可以直接通过kube-apiserver
访问仪表盘,我也试了一下,访问地址如下。
https://192.168.1.200:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
我也只是出于好奇,访问了一下试试,确实可以,认证登陆之后一切正常,而且随便找一个pod
可以远程执行命令了。
我这里用的是Chrome
,这时候大概有点思绪了,要么是FireFox
的问题,再要么就是证书有问题,我就在好奇我好像没给仪表盘创建证书哇,先是看了一眼仪表盘证书的详情,用FireFox
看的。
这。。。我没印象有给仪表盘生成过证书哇,我在好奇这个证书是在哪里来的,我仔细翻了一下创建仪表盘的yaml
文件,发现这个证书是一个空的secret
,被挂到了pod
的/certs
目录
确实是空的,我感觉就是证书的问题了,既然这样,那就自己生成一个吧,或是随便找一个现有的,先把仪表盘删了吧。
[root@master-1 /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard]# kubectl delete -f .
删除后先编辑dashboard-secret.yaml
文件,将这一段注释掉,保存退出。
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
# Allows editing resource and makes sure it is created first.
addonmanager.kubernetes.io/mode: EnsureExists
name: kubernetes-dashboard-certs
namespace: kube-system
type: Opaque
data:
---
随便找一个目录,生成一个吧。
[root@master-1 ~]# mkdir demo/dashboard && cd demo/dashboard
[root@master-1 ~/demo/dashboard]# openssl genrsa -out dashboard.key 2048
[root@master-1 ~/demo/dashboard]# openssl req -new -out dashboard.csr -key dashboard.key -subj '/CN=192.168.1.200'
[root@master-1 ~/demo/dashboard]# openssl x509 -req -days 3650 -in dashboard.csr -signkey dashboard.key -out dashboard.crt
[root@master-1 ~/demo/dashboard]# openssl x509 -in dashboard.crt -text -noout
然后手动创建一个名为kubernetes-dashboard-certs
的secret
,在kube-system
命名空间,直接用命令创建了。
[root@master-1 ~/demo/dashboard]# kubectl create secret generic -n kube-system kubernetes-dashboard-certs --from-file=./dashboard.crt --from-file=./dashboard.key
secret/kubernetes-dashboard-certs created
然后重新部署一下dashboard
就可以了。
[root@master-1 ~/demo/dashboard-keys]# kubectl create -f /usr/local/kubernetes/soft/kubernetes/cluster/addons/dashboard/
在访问一下看看就可以继续前往了,
远程执行命令试试
没得问题,这样仪表盘才算是正常了,暂时就这样,下面开始部署多Master
集群。
多Master集群
多Master
架构如下。
生产使用的话最好是保证Master
是高可用的,对于单Master
相对复杂,Etcd
已经是高可用了,master
如果挂了就无法管理集群了,有些功能也用不了了,所以要部署多Master
,master
高可用主要在于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
,写配置文件,启动服务,按着环境规划,我用的VIP
是207
,我的操作如下。
[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 {
your@email
}
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
集群就搭建好了,本篇结束。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。