kubernetes 简介以及安装安装高可用v1.13.1集群(一)

kubectl-cheatsheet

Kubernetes是谷歌开源的容器集群管理系统,是Google多年大规模容器管理技术Borg的开源版本,也是CNCF最重要的项目之一,主要功能包括:

  • 基于容器的应用部署、维护和滚动升级
  • 负载均衡和服务发现
  • 跨机器和跨地区的集群调度
  • 自动伸缩
  • 无状态服务和有状态服务
  • 广泛的Volumn支持
  • 插件机制保证扩展性

Kubernetes架构

Kubernetes主要由以下几个核心组件组成:

  • etcd保存了整个集群的状态;
  • apiserver提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制;
  • controller manager负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;
  • scheduler负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上;
  • kubelet负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理;
  • Container runtime负责镜像管理以及Pod和容器的真正运行(CRI);
  • kube-proxy负责为Service提供cluster内部的服务发现和负载均衡

Kubeadm 1.13 安装高可用 kubernetes v1.13.1 集群

kubernetes-dashboard

先上图给个肯定信心。

部署

以CentOS7为基础,搭建一个Master主机和三个Node主机,各个Node主机的配置方式基本相同。

  • OS: CentOS 7.5 x86_64
  • Container runtime: Docker 18.06.ce
  • Kubernetes: 1.13
IP 地址 主机名 角色
192.168.50.71 master, master.kubernetes.io master
192.168.50.72 node01, node01.kubernetes.io node
192.168.50.73 node02, node02.kubernetes.io node
192.168.50.74 node03, node03.kubernetes.io node

这里需要使用常规的域名格式,因为后面需要为集群配置Kubernetes Dashboard要求有SSL数字签名。

系统配置

配置host,

1
2
3
4
5
cat /etc/hosts
192.168.50.71 master master.kubernetes.io
192.168.50.72 node1 node01.kubernetes.io
192.168.50.73 node2 node02.kubernetes.io
192.168.50.74 node3 node03.kubernetes.io

关闭防火墙,选择iptable加入端口或禁用防火墙服务两种方式。这里简单起见,禁用防火墙:

1
2
sudo systemctl stop firewalld
sudo systemctl disable firewalld

禁用SELINUX,

1
2
3
sudo setenfore 0
sudo vi /etc/selinux/config
SELINUX=disabled

所有节点关闭交换分区,

1
2
sudo swapoff -a
sudo vi /etc/fstab

将交换区注释掉,使用free -m查看交换分区是否关闭。

创建/etc/sysctl.d/k8s.conf文件,添加如下内容,

1
2
3
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
net.ipv4.ip_forward=1

执行命令使修改生效,

1
2
sudo modprobe br_netfilter
sudo sysctl -p /etc/sysctl.d/k8s.conf

kube-proxy开启ipvs,Kubernetes 1.11之后的版本默认支持使用ipvs代理模式的Service资源,但它依赖ipvs相关的内核模块,这些模块默认不会自动载入。kube-proxy开启ipvs的前提需要加载以下模块:

1
2
3
4
5
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack_ipv4

创建/etc/sysconfig/modules/ipvs.modules文件,内容如下

1
2
3
4
5
6
7
8
#!/bin/bash
ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs"
for i in $(ls $ipvs_mods_dir | grep -o "^[^.]*"); do
/sbin/modinfo -F filename $i &> /dev/null
if [ $? -eq 0 ]; then
/sbin/modprobe $i
fi
done

修改文件权限,并加载内核模块,

1
2
sudo chmod +x /etc/sysconfig/modules/ipvs.modules
sudo /etc/sysconfig/modules/ipvs.modules

注意该步骤不是必须的,因为ipvs仅负责负载均衡相关任务,它无法完成kube-proxy中的包过滤机SNAT等功能,这些仍需要由iptables实现。也就是说,如果条件不满足,即使kube-proxy开启了ipvs模式,也会回退到iptables模式。

安装Docker

Docker的安装可以参考阿里云的docker-ce的安装方法,目前Kubernetes推荐的最新支持的docker版本为18.06,注意不要使用不兼容的版本。

如果你有阿里云账号,可以参考镜像加速器方法。

另外,如果想通过外网访问Docker,可以在Systemd加入启动参数配置sock进行访问

1
2
3
4
5
sudo vim /lib/systemd/system/docker.service

[Service]
...
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375

其它细节可以参考阿里docker相关文档。

配置外网访问SS

首先,你得先有一个SS,因为大陆内目前访问不了k8s.gcr.io。虽然有人做了镜像同步,对同步的镜像进行retag也是可行的方式,但我有SS!!

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo yum install python-pip epel-release -y
sudo pip install shadowsocks
cat > /etc/shadowsocks.json <<EOF
{
"server":"xx.xx.xx.xx",
"server_port": 443,
"local_port": 1080,
"password":"xxx",
"timeout":600,
"method":"aes-256-cfb"
}
EOF
sudo sslocal -c /etc/shadowsocks.json -d start

SS主要是配给Docker用的,编辑/lib/systemd/system/docker.service文件,

1
2
3
Environment="HTTP_PROXY=socks5://127.0.0.1:1080/"
Environment="HTTPS_PROXY=socks5://127.0.0.1:1080/"
Environment="NO_PROXY=localhost,127.0.0.0/8,guqcep47.mirror.aliyuncs.com"

kubelet,kubeadm,kubectl安装

首先要设定组件的仓储,编辑/etc/yum.repos.d/kubernetes.repo,内容如下,

1
2
3
4
5
6
7
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=1
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

执行如下命令安装程序包,

1
sudo yum install kubelet kubeadm kubectl

kubernetes自1.8版本开始,强制要求关闭系统swap,编辑kubelet配置文件/etc/sysconfig/kubelet,忽略禁止使用Swap限制,

1
KUBELET_EXTRA_ARGS="--fail-swap-on=false"

加入启动服务,

1
2
sudo systemctl start kubelet
sudo systemctl enable kubelet

集群初始化

集群初始化动作需要在Master进行,然后在其它Node节点使用join加入,所以这里的命令行需要在各个主机单独敲命令了。

有两种初始化方式,一种是命令带参数方式;另一种是使用配置文件,两种方式是等效的,

1
sudo kubeadm init --kubernetes-version=v1.13.2 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --apiserver-advertise-address=0.0.0.0 --ignore-preflight-errors=Swap

简单说一下这几个重要的参数,

  • --kubernetes-version:Kubernete的版本
  • --pod-network-cidr:Pod网络地址范围,其值为CIDR格式的网络地址;使用flannel网络插件是,默认地址为10.244.0.0/16。
  • --service-cidr:Service的网络地址范围,其值为CIDR格式的网络地址,默认地址为10.96.0.0/12。
  • --apiserver-advertise-address:API server通告给其他组件的IP地址,一般应该为Master节点的IP地址,0.0.0.0表示节点上的所有可用地址。
  • --ignore-preflight-errors:忽略哪些运行时的错误信息,其值为Swap时,表示忽略因swap未关闭而导致的错误。

一般情况下,都是使用配置文件的方式,可以通过下面的命令查看一份完整的kubeadm配置示例,

1
sudo kubeadm config print init-defaults --component-configs KubeProxyConfiguration

存储输出的内容为kubeadm-config.yaml,根据自己需求修改,执行命令初始化

1
sudo kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=Swap

初始化如果成功,会打印两个重要信息,一是

1
2
3
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOEM/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

照着写便是,默认情况下kubectl会从当前用户主目录的.kube下的config读取配置信息,包括Kubernetes集群、证书或令牌等。集群初始化时,kubeadm会自动生成一个用于此类功能的配置文件/etc/kubernetes/admin.conf,将它复制为$HOME/.kube/config文件即可直接使用。

kubectl有非常多的子命令,其中“get compontsstatuses”可显示集群组件当前的状态,简写为get cs

1
2
3
4
5
6
7
kubectl get cs

NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health": "true"}

若命令结果的STATUS字段为“Healthy”,表示组件处于健康运行状态,否则需要检查其错误所在,必要时使用“kubeadm reset”命令重置重新进行初始化。

另外使用kubectl get nodes,获取集群节点的相关状态信息,例如

1
2
3
4
kubectl get nodes

NAME STATUS ROLES AGE VERSION
kubernetes-master NotReady master 7d5h v1.13.2

为Kubernetes提供的Pod网络插件非常多,目前流行的有flannel和Calico。flannel运行为Kubernetes集群的附件,它以Pod的形式部署运行与每个集群节点上以接受Kubernetes集群管理。事实上,flannel也可以以守护进程方式运行在各个节点,即以非托管的方式运行。部署命令使kubectl applykubectl crreate,下面是使用在线的方式进行flannel部署:

1
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

部署成功会出现created字样,配置flannel网络插件时,Master节点上的Docker首先会去获取flannel镜像文件,而后根据镜像文件启动相应的Pod对象。现在再次查看Master已经变为“Ready”状态:

1
2
3
4
kubectl get nodes

NAME STATUS ROLES AGE VERSION
kubernetes-master Ready master 7d5h v1.13.2

可通过,

1
kubectl get pods -n kube-system | grep flannel

显示网络插件flannel的Pod状态情况。

集群初始化时,另一个信息是产生一段token信息,这段信息用于Node节点加入Master。

1
sudo kubeadm join kubernetes-master:6443 --token 0qpyy8.iv5v2uhhrjy3wsri --discovery-token-ca-cert-hash sha256:c8ad1e333b6e2e1185ea2ab7beb97b90022f8285e79a1cc6a7e71ad772748f42 --ignore-preflight-errors=Swap

每个节点加入到Master之后,再次通过kubectl get nodes查看节点信息,

1
2
3
4
5
6
7
kubectl get nodes

NAME STATUS ROLES AGE VERSION
kubernetes-master Ready master 7d5h v1.13.2
kubernetes-node1 Ready <none> 7d4h v1.13.2
kubernetes-node2 Ready <none> 7d4h v1.13.2
kubernetes-node3 Ready <none> 7d4h v1.13.2

至此,Kubernetes集群的部署已经完成,后续有更多节点加入时,均可使用此方式。

Kubernetes的命令非常多,在文章最前面的大图已经描述清楚。由于这里仅介绍集群安装内容,下面简单了解下关于集群方面的命令,

获取集群信息,

1
2
3
4
5
kubectl cluster-info
Kubernetes master is running at https://192.168.50.71:6443
KubeDNS is running at https://192.168.50.71:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

版本信息,

1
2
3
kubectl version --short=true
Client Version: v1.13.2
Server Version: v1.13.2

移除节点,

1
2
kubectl drain NODE_ID --delete-local-data --force --ignore-daemonsets
kubectl delete node NODE_ID

重置节点,

1
kubeadm reset

部署高可用CoreDNS

默认安装的CoreDNS存在单点问题。在Master节点查看kubectl get pods -n kube-system -owide分布如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kubectl get pods -n kube-system -owide 
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-86c58d9df4-6j2m6 0/1 ContainerCreating 0 90m <none> master.kubernetes.io <none> <none>
coredns-86c58d9df4-glvnp 0/1 ContainerCreating 0 90m <none> master.kubernetes.io <none> <none>
etcd-master.kubernetes.io 1/1 Running 2 89m 192.168.50.71 master.kubernetes.io <none> <none>
kube-apiserver-master.kubernetes.io 1/1 Running 2 89m 192.168.50.71 master.kubernetes.io <none> <none>
kube-controller-manager-master.kubernetes.io 1/1 Running 2 89m 192.168.50.71 master.kubernetes.io <none> <none>
kube-flannel-ds-amd64-czh7z 1/1 Running 0 80m 192.168.50.73 node02.kubernetes.io <none> <none>
kube-flannel-ds-amd64-gcqkk 1/1 Running 0 80m 192.168.50.74 node03.kubernetes.io <none> <none>
kube-flannel-ds-amd64-lk5dw 1/1 Running 0 81m 192.168.50.72 node01.kubernetes.io <none> <none>
kube-flannel-ds-amd64-xp5xf 0/1 PodInitializing 0 83m 192.168.50.71 master.kubernetes.io <none> <none>
kube-proxy-b82sn 1/1 Running 0 80m 192.168.50.73 node02.kubernetes.io <none> <none>
kube-proxy-ql6hp 1/1 Running 0 81m 192.168.50.72 node01.kubernetes.io <none> <none>
kube-proxy-sh87s 1/1 Running 0 80m 192.168.50.74 node03.kubernetes.io <none> <none>
kube-proxy-w2kv4 0/1 ContainerCreating 0 90m 192.168.50.71 master.kubernetes.io <none> <none>
kube-scheduler-master.kubernetes.io 1/1 Running 2 89m 192.168.50.71 master.kubernetes.io <none> <none>

删除原来的单点CoreDNS,

1
kubectl delete deploy coredns -n kube-system

创建一份多实例配置coredns-ha.yaml,内容如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: kube-dns
name: coredns
namespace: kube-system
spec:
#集群规模可自行配置
replicas: 2
selector:
matchLabels:
k8s-app: kube-dns
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
k8s-app: kube-dns
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- kube-dns
topologyKey: kubernetes.io/hostname
containers:
- args:
- -conf
- /etc/coredns/Corefile
image: registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.2.6
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 5
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: coredns
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- all
readOnlyRootFilesystem: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/coredns
name: config-volume
readOnly: true
dnsPolicy: Default
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: coredns
serviceAccountName: coredns
terminationGracePeriodSeconds: 30
tolerations:
- key: CriticalAddonsOnly
operator: Exists
- effect: NoSchedule
key: node-role.kubernetes.io/master
volumes:
- configMap:
defaultMode: 420
items:
- key: Corefile
path: Corefile
name: coredns
name: config-volume

执行,

1
kubectl apply -f coredns-ha.yaml

再次查看分布,

1
2
3
4
5
6
7
kubectl get pods -n kube-system -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-6c67f849c7-jhqhj 1/1 Running 0 3m6s 10.244.1.3 node01.kubernetes.io <none> <none>
coredns-6c67f849c7-kxtkw 1/1 Running 0 3m6s 10.244.3.4 node03.kubernetes.io <none> <none>
etcd-master.kubernetes.io 1/1 Running 2 102m 192.168.50.71 master.kubernetes.io <none> <none>
kube-apiserver-master.kubernetes.io 1/1 Running 2 102m 192.168.50.71 master.kubernetes.io <none> <none>
kube-controller-manager-master.kubernetes.io 1/1 Running 2 102m 192.168.50.71 master.kubernetes.io <none> <none>

CoreDNS的Pod落在节点node1和node3上了。

安装dashboard

Kubernetes dashboard的安装也是在pod上的,所以要在所有节点执行,

1
sudo docker pull k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1

下载官方推荐的部署文件,

1
wget https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml

因为前面我已经将镜像拉取下来了,所以不必要再拉取,修改这个kubernetes-dashboard.yaml文件,

1
2
3
4
5
6
7
8
9
spec:
containers:
- image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1
imagePullPolicy: Never
name kubernetes-dashboard
ports:
- containerPort: 8443
dnsPolicy: ClusterFirst
restartPolicy: Always

另外,需要暴露端口以给集群外部访问,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ------------------- Dashboard Service ------------------- #

kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
spec:
type: NodePort
ports:
- port: 443
targetPort: 8443
nodePort: 31234
selector:
k8s-app: kubernetes-dashboard

OK,执行命令部署pod,

1
kubectl create -f kubernetes-dashboard.yaml

查看一下dashboard的pod是否正常启动,如果正常,说明安装成功,

1
kubectl get pods -n kube-system -owide

kube-system

查看外网暴露的端口,

1
2
3
4
kubectl get services -n kube-system                                                                        
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 7d5h
kubernetes-dashboard NodePort 10.104.42.80 <none> 443:31234/TCP 138m

默认情况下,kubeadm创建集群时已经创建了admin角色,我们直接绑定即可,

创建一个admin-user-role-binding.yaml文件,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: admin
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: admin
namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile

执行,

1
kubectl create -f admin-user-role-binding.yaml

获取token,

1
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')

把Token复制的登录界面,即可。

这里登录时有个问题,就是HTTPS访问没有证书,chrome直接不让访问!Firefox还好可以绕过。所以需要自己加一个证书,

首先生成私钥和证书签名,

1
2
grep 'client-key-data' ~/.kube/config | head -n 1 | awk '{print $2}' | base64 -d >> dashboard.key
grep 'client-certificate-data' ~/.kube/config | head -n 1 | awk '{print $2}' | base64 -d >> dashboard.crt

生成证书,

1
openssl pkcs12 -export -clcerts -inkey dashboard.key -in dashboard.crt -out dashboard.p12 -name "kubernetes-client"

将生成的dashboard.keydashboard.crt放置在路径/certs下, 重新配置

1
2
kubectl create -f kubernetes-dashboard.yaml
kubectl create -f admin-user-role-binding.yaml

虽然添加了证书,但也仅能通过firefox添加例外访问,chrome根本不信任你。所以生产环境上还是要买一个SSL证书,另外Pod内的service最好也不要直接暴露给外网访问,一般用nginx-ingress做个代理。


  1. 你可能需要安装额外的工具用于Kubernetes管理,参考这里