基于 Kubeadm 的 Kubernetes 搭建手册

摘要:本文介绍如何使用 Kubeadm 手动搭建 Kubernetes 以及注意事项。

概述

研究了 MiniKube 之后,感觉如果想进一步深入的学习 Kubernetes, 还是需要自己搭建一个生产环境的集群。虽然现在云端产品有很多 Kubernetes 的服务,但是毕竟是收费的。

通过学习和了解 Kubernetes 的官网,发现了很多的解决方法,但是尝试了几个发现其教程十分不完善,遇到问题没有什么支持。比如使用 Fedora 搭建就会有网络问题。使用 Ubuntu 的 MAAS 搭建,发现需要了解很多概念,比如 Juju 等等。最终通过搜索发现这篇教程十分详细 How To Create a Kubernetes 1.11 Cluster Using Kubeadm on Ubuntu 18.04 在搭建的过程中只遇到了几个小问题。并且最后进行了一些简单的扩展。

下面简要列出搭建的大纲以及遇到的问题。

搭建概要

首先列出大纲

  1. Ubuntu 系统准备
  2. Ansible 安装
  3. Ansible Host file
  4. Initial Ubuntu by Ansible
  5. 安装 Kubernetes 相关依赖 by Ansible
  6. 配置 Master Node by Ansible
  7. 配置 Worker Node by Ansible
  8. 验证集群
  9. 通过部署 Nginx 应用验证集群
  10. 安装 Kubernetes DashBoard

Ubuntu 系统准备

使用 Ubuntu Server 18.04 LTS 版本,现在版本的安装十分简单,基本只需要配置一下网络。

这里需要安装 3 台 Ubuntu Server,一台作为 Master Node,另外两台作为 Worker Nodes

SSH

对于 Linux Server 的安装,基本 SSHD 是一个默认启动的服务,所以安装完成后,就可以直接通过用户名和密码 SSH 登陆到系统,但是如果希望使用 Public Key 登陆,就需要自己更改配置文件以及添加自己的 Public Key 到对应用户的 Home 目录下的 ~/.ssh/authorized_keys 文件中。

这里推荐使用一个叫做 LaunchPad 的网站,由于 Public Key 是可以公开出去,所以我们可以把自己的 Public Key 发布到这个网站,然后在 Ubunut 安装的时候,在创建用户这一步,有一个选项,叫做导入 SSH,其中可以选择这个网站,然后安装过程中就会自动从这个网站上将我们的 Public Key 下载下来,然后询问是否添加到 authorized_keys 这个文件中,如果我们确认 Public Key 无误后,点击确定,这时候这个 Public Key 就会自动配置后,就可以直接通过 Public Key 登陆到系统了,十分方便。

Ansible 安装

十分简单,直接参考官方文档: How to Install and Configure Ansible on Ubuntu 18.04

简单的了解 Ansible Configuration Management 101: Writing Ansible Playbooks.

这里我们可以把它想象成一个脚本命令执行器,我们定义好脚本执行的步骤,然后 Ansible 通过这个步骤,借助 SSH 在指定的服务器上执行对应的脚本命令,

Ansible Host file

创建文件 touch ~/kube-cluster/hosts

1
2
3
4
5
6
7
8
9
[masters]
master ansible_host=master_ip ansible_user=root

[workers]
worker1 ansible_host=worker_1_ip ansible_user=root
worker2 ansible_host=worker_2_ip ansible_user=root

[all:vars]
ansible_python_interpreter=/usr/bin/python3

这样我们在执行 Ansible 命令的时候只需要指定这个问题,就可以在指定的服务器上进行操作了。

1
ansible-playbook -i hosts OTHER_CONFIG

Initial Ubuntu by Ansible

创建文件 touch ~/kube-cluster/initial.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- hosts: all
become: yes
tasks:
- name: create the 'ubuntu' user
user: name=ubuntu append=yes state=present createhome=yes shell=/bin/bash

- name: allow 'ubuntu' to have passwordless sudo
lineinfile:
dest: /etc/sudoers
line: 'ubuntu ALL=(ALL) NOPASSWD: ALL'
validate: 'visudo -cf %s'

- name: set up authorized keys for the ubuntu user
authorized_key: user=ubuntu key="{{item}}"
with_file:
- ~/.ssh/id_rsa.pub

这里就是创建了一个叫做 ubuntu 的用户,同时将当前默认 public key 添加到 sshd 的信任列表中。另外这里还将 ubuntu 用户的 sudo 命令设置为不需要密码,这样可以在执行 sudo 命令的时候不需要交互密码。

安装 Kubernetes 相关依赖 by Ansible

这里我们需要明白 Kubernetes 相关组件的用途:

  • Docker - a container runtime. It is the component that runs your containers. Support for other runtimes such as rkt is under active development in Kubernetes.

  • kubeadm - a CLI tool that will install and configure the various components of a cluster in a standard way. 这是一个用于安装和配置 Kubernetes 的命令行工具

  • kubelet - a system service/program that runs on all nodes and handles node-level operations. 这是 Kubernetes 的 Node 运行的服务

  • kubectl - a CLI tool used for issuing commands to the cluster through its API Server. 这是 Kubernetes 的 Master 运行的服务

创建文件 touch ~/kube-cluster/kube-dependencies.yml

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
- hosts: all
become: yes
tasks:
- name: install Docker
apt:
name: docker.io
state: present
update_cache: true

- name: install APT Transport HTTPS
apt:
name: apt-transport-https
state: present

- name: add Kubernetes apt-key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present

- name: add Kubernetes' APT repository
apt_repository:
repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
state: present
filename: 'kubernetes'

- name: install kubelet
apt:
name: kubelet
state: present
update_cache: true

- name: install kubeadm
apt:
name: kubeadm
state: present

- hosts: master
become: yes
tasks:
- name: install kubectl
apt:
name: kubectl
state: present

所有节点: Dockerkubeletkubeadm
Master节点: kubectl

注意事项

作为这一步,需要做额外两步:

  1. 需要解决 Docker 的权限问题,这时候使用 ubuntu 运行 docker ps,会出现权限问题,需要将 ubuntu 加入到 docker group 中,在 ubuntu 用户中执行命令: sudo usermod -a -G docker $USER,然后需要 logout 在 login 才会生效。
  2. 需要关闭 swapoff,否则下面的 kuberadm init 会出错。 sudo swapoff -a

配置 Master Node by Ansible

创建文件 touch ~/kube-cluster/master.yml

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
- hosts: master
become: yes
tasks:
- name: initialize the cluster
shell: kubeadm init --pod-network-cidr=10.244.0.0/16 >> cluster_initialized.txt
args:
chdir: $HOME
creates: cluster_initialized.txt

- name: create .kube directory
become: yes
become_user: ubuntu
file:
path: $HOME/.kube
state: directory
mode: 0755

- name: copy admin.conf to user's kube config
copy:
src: /etc/kubernetes/admin.conf
dest: /home/ubuntu/.kube/config
remote_src: yes
owner: ubuntu

- name: install Pod network
become: yes
become_user: ubuntu
shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml >> pod_network_setup.txt
args:
chdir: $HOME
creates: pod_network_setup.txt

主要就做了3件事情:

  1. kubeadm 初始化
  2. 复制初始化后生成的配置文件到当前用户的目录,并设置环境变量
  3. 配置网络

这三个步骤完全和其他教程的 kuberadm 配置是一致的。

执行完成后我们会有两个文件:

  1. root 用户目录:cluster_initialized.txt
  2. ubunut 用户目录: pod_network_setup.txt

第一个文件十分重要,里面有 kubuernet 初始化的信息,以及后续操作指导,比如拷贝配置文件和如何将 worker node 加入到该集群。

这时候我们就可以验证下 Master Node 是否启动成功 kubectl get nodes,状态需要是 Ready

1
2
NAME      STATUS    ROLES     AGE       VERSION
master Ready master 1d v1.11.1

配置 Worker Node by Ansible

创建文件 touch ~/kube-cluster/workers.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- hosts: master
become: yes
gather_facts: false
tasks:
- name: get join command
shell: kubeadm token create --print-join-command
register: join_command_raw

- name: set join command
set_fact:
join_command: "{{ join_command_raw.stdout_lines[0] }}"


- hosts: workers
become: yes
tasks:
- name: join cluster
shell: "{{ hostvars['master'].join_command }} >> node_joined.txt"
args:
chdir: $HOME
creates: node_joined.txt

实际上我们通过上一步生成的问题中的命令在 worker 节点上执行一下就可以加入到集群,这里通过命令来重新获取 token 来自动化执行。

kubeadm token create --print-join-command 命令会创建 token,并且打印出加入节点的命令,然后使用 Ansible 将其存入变量:join_command_raw,然后在 worker 节点上直接执行该命令就可以了。

验证集群

Master 节点: kubectl get nodes

1
2
3
4
NAME      STATUS    ROLES     AGE       VERSION
master Ready master 1d v1.11.1
worker1 Ready <none> 1d v1.11.1
worker2 Ready <none> 1d v1.11.1

通过部署 Nginx 应用验证集群

1
2
3
4
5
6
7
8
9
10
kubectl run nginx --image=nginx --port 80

kubectl expose deploy nginx --port 80 --target-port 80 --type NodePort

kubectl get services


NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 1d
nginx NodePort 10.109.228.209 <none> 80:nginx_port/TCP 40m

安装 Kubernetes DashBoard

参考 Kubernetes DashBoard文档 ,安装 Kubernetes DashBoard

如果是本机运行,很简单,只需要两步:

  1. 应用配置
  2. 配置 proxy
1
2
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
kubectl proxy

这时候在 Master 节点,就可以直接访问 http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/

Kubernetes DashBoard Access Outside

参考:

access outside: https://github.com/kubernetes/dashboard/wiki/Accessing-Dashboard---1.7.X-and-above

user and token: https://github.com/kubernetes/dashboard/wiki/Creating-sample-user

这里有两种方法:

proxy
1
kubectl proxy --address 0.0.0.0 --accept-hosts '.*' &

也就是配置 proxy 为接受任何 host。但是这用方法暴露的是 http,所以不支持用户登陆。

NOTE: Dashboard should not be exposed publicly over HTTP. For domains accessed over HTTP it will not be possible to sign in. Nothing will happen after clicking Sign in button on login page.

NodePort

使用 NodePort 方法暴露 Dashboard 服务

1
kubectl -n kube-system edit service kubernetes-dashboard

修改配置文件中 spec 中的 type: ClusterIPtype: NodePort

1
2
3
4
5
6
7
8
9
10
11
12
spec:
clusterIP: 10.100.124.90
externalTrafficPolicy: Cluster
ports:
- port: 443
protocol: TCP
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
sessionAffinity: None
#type: ClusterIP
type: NodePort

然后我们获取端口号

1
2
3
4
kubectl -n kube-system get service kubernetes-dashboard

NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard 10.100.124.90 <nodes> 443:31707/TCP 21h

这时候我们就可以使用 Master 节点的 IP 加上上面的端口号 31707 来访问 DashBoard

创建用户登陆

如果使用上面第二种方法暴露 Dashboard 服务,我们就可以使用登陆功能,参考文档创建用户并生成token

创建用户配置文件

用户名为: admin-user

1
2
3
4
5
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kube-system

执行:

1
kubectl apply -f dashboard-adminuser.yaml
创建ClusterRoleBinding配置文件
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kube-system

执行

1
kubectl apply -f dashboard-cluster-role-biding.yaml
生成 token

创建一个 shell 脚本: genToken.sh

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

使用脚本

1
./genToken admin-user >> admin-user.token

这时候就可以用这个 token 登陆了。