Kubernetes(常简称为K8s)是用于自动部署、扩展和管理容器化(containerized)应用程序的开源系统。Google设计并捐赠给Linux基金会来使用的。它旨在提供“跨主机集群的自动部署、扩展以及运行应用程序容器的平台”。它支持一系列容器工具, 包括Docker等。
kubeadm
支持多种系统,这里简单介绍一下需要的系统要求:
具体的详细信息可以在官方网站上看到。
本篇内容基于aws的ap-northeast-1的ec2, CentOS7
的操作系统(ami-4dd5522b),实例类型t2.medium 2核4GB,3台机器,1 master,2 nodes,kubernetes 1.9 版本。为了方便起见,在安全组里面打开了所有的端口和IP访问。
机器配置:
[centos@ip-172-31-24-49 ~]$ uname -a
Linux ip-172-31-24-49.ap-northeast-1.compute.internal 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
首先 ,我们关闭selinux:
$ sudo vim /etc/sysconfig/selinux
把SELINUX改成disabled,然后保存退出。
在我用的ami中,swap是默认关闭的,所以不需要我手动关闭,大家需要确认 自己的环境中swap是否有关闭掉,否则会在之后的环节中出问题。
为了方便我们安装,我们将sshd设置为keepalive:
$ sudo -i
$ echo "ClientAliveInterval 10" >> /etc/ssh/sshd_config
$ echo "TCPKeepAlive yes" >> /etc/ssh/sshd_config
$ systemctl restart sshd.service
接下来我们重启一下机器:
$ sudo sync
$ sudo reboot
至此,准备阶段结束。
首先,我们需要在所有机器上都安装 docker
, kubeadm
, kubelet
和 kubectl
。
切记:kubeadm不会自动去安装和管理 kubelet和kubectl,所以需要自己去确保安装的版本和你想要安装的kubernetes版本相同。
安装 docker
:
$ sudo yum install -y docker
$ sudo systemctl enable docker && sudo systemctl start docker
在RHEL/CentOS 7 系统上可能会路由失败,我们需要设置一下:
$ sudo -i
$ cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sudo sysctl --system
接下来我们需要安装 kubeadm
, kubelet
和 kubectl
了,我们需要先加一个repo:
$ cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
然后安装:
$ sudo yum install -y kubelet kubeadm kubectl
$ sudo systemctl enable kubelet && sudo systemctl start kubelet
至此,在所有机器上安装所需的软件已经结束。
安装完所有的依赖之后,我们就可以用 kubeadm
初始化master了。
最简单的初始化方法是:
$ kubeadm init
除此之外, kubeadm
还支持多种方法来配置,具体可以查看一下官方文档。
我们在初始化的时候指定一下kubernetes版本,并设置一下pod-network-cidr(后面的flannel会用到):
$ sudo -i
$ kubeadm init --kubernetes-version=v1.9.0 --pod-network-cidr=10.244.0.0/16
在这个过程中 kubeadm
执行了一系列的操作,包括一些pre-check,生成ca证书,安装etcd和其它控制组件等。
界面差不多如下:
最下面的这行 kubeadm join
什么的,就是用来让别的node加入集群的,可以看出非常方便。我们要保存好这一行东西,这是我们之后让node加入集群的凭据,一会儿会用到。
这个时候,我们还不能通过 kubectl
来控制集群,要让 kubectl
可用,我们需要做:
# 对于非root用户
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 对于root用户
$ export KUBECONFIG=/etc/kubernetes/admin.conf
# 也可以直接放到~/.bash_profile
$ echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
接下来要注意,我们必须自己来安装一个network addon。
network addon必须在任何app部署之前安装好。同样的,kube-dns也会在network addon安装好之后才启动。kubeadm只支持CNI-based networks(不支持kubenet)。
比较常见的network addon有: Calico
, Canal
, Flannel
, Kube-router
, Romana
, WeaveNet
等。这里我们使用 Flannel
。
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml
安装完network之后,你可以通过 kubectlgetpods--all-namespaces
来查看 kube-dns
是否在running来判断network是否安装成功。
默认情况下,为了保证master的安全,master是不会被调度到app的。你可以取消这个限制通过输入:
$ kubectl taint nodes --all node-role.kubernetes.io/master-
终于部署完了我们的master!
现在我们开始加入一些node到我们的集群里面吧!
ssh到我们的node节点上,执行刚才下面给出的那个 kubeadm join
的命令(每个人不同):
$ sudo -i
$ kubeadm join --token 72a8a4.2ed9076cd668b8b7 172.31.31.60:6443 --discovery-token-ca-cert-hash sha256:f0894e55d475f882dd40d52c6d01f758017ec5729be632294049f687330f60d2
输出差不多如下图:
这时候,我们去master上输入 kubectlgetnodes
查看一下:
[root@i-071abd86ed304dc84 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
i-071abd86ed304dc84 Ready master 12m v1.9.0
i-0c559ad3c0b16fd36 Ready <none> 1m v1.9.0
i-0f3f7462b0a004b5e Ready <none> 47s v1.9.0
群集将包含以下物理资源:
主节点(Kubernetes中的节点指的是服务器)负责管理集群的状态。我们将用它运行Etcd,该服务器目的是将工作负载调度到工作节点的组件之间存储集群数据。
工作节点是运行工作负载(即容器化应用程序和服务)的服务器。一旦工作节点分配了工作负载,工作节点将继续运行您的工作负载,即使计划在调度完成后停止工作也是如此。通过添加工作节点可以增加群集的容量。
完成本教程后,您将拥有一个可以运行容器化应用程序的集群,前提是集群中的服务器具有足够的CPU和RAM资源供应用程序使用。几乎任何传统的Unix应用程序(包括Web应用程序,数据库,守护程序和命令行工具)都可以进行容器化,并在集群上运行。群集本身将在每个节点上消耗大约300-500MB的内存和10%的CPU。
设置群集后,您将部署Web服务器Nginx以确保它正确运行。
在本节中,您将在本地计算机上创建一个用作工作区的目录。您还将在本地配置Ansible,以便它可以与远程服务器上的命令进行通信。为此,您将创建一个hosts
文件包,其包含例如服务器的IP地址和每个服务器所属的组等信息。
在三台服务器中,一台服务器将作为主服务器master_ip
。另外两台服务器则是是工作节点,并拥有IPworker_1_ip
和worker_2_ip
。
在本地计算机的主目录中创建一个名为~/kube-cluster/hosts
的目录并进入其中:
mkdir ~/kube-cluster
cd ~/kube-cluster
该目录将是本教程的工作区,包含所有Ansible
设置。它也将是您运行所有本地命令的目录。
使用vi
命令创建一个名为~/kube-cluster/hosts
的文件或用您最喜欢的文本编辑器:
vi ~/kube-cluster/hosts
按i
将以下文本插入到文件中,该文件将指定有关群集逻辑结构的信息:
[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
完成后,按,ESC然后输入:wq
将更改写入文件并退出。
您可能还记得在Ansible中用于指定服务器信息的库存文件,例如IP地址,远程用户和服务器分组,以作为执行命令的单个单元进行目标。~/kube-cluster/hosts
将是您的库存文件,并且您已向其添加了两个Ansible组(主服务器和工作服务器),用于指定集群的逻辑结构。
在主服务器组中,有一个名为“master”的服务器,其中列出了主节点的IP(master_ip
),并指定Ansible应以根用户身份运行远程命令。
同样,在workers组中,有两个工作服务器(worker_1_ip
和worker_2_ip
),它们也需要指定ansible_user
为root用户。
在设置服务器清单之后,让我们继续安装操作系统级依赖关系并创建配置设置。
在本节中,您将使用CentOS的yum软件包管理器安装Kubernetes所需的软件包。这些包是:
kubeadm
- CLI工具,以标准方式安装和配置群集的各个组件。kubelet
- 在所有节点上运行并处理节点级操作的系统服务/程序。kubectl
- 通过其API服务器向集群发出命令的CLI工具。创建工作空间中指定的文件vi ~/kube-cluster/kube-dependencies.yml
:
vi ~/kube-cluster/kube-dependencies.yml
将下面的内容插到文件内:
- hosts: all
become: yes
tasks:
- name: install Docker
yum:
name: docker
state: present
update_cache: true
- name: start Docker
service:
name: docker
state: started
- name: disable SELinux
command: setenforce 0
- name: disable SELinux on reboot
selinux:
state: disabled
- name: ensure net.bridge.bridge-nf-call-ip6tables is set to 1
sysctl:
name: net.bridge.bridge-nf-call-ip6tables
value: 1
state: present
- name: ensure net.bridge.bridge-nf-call-iptables is set to 1
sysctl:
name: net.bridge.bridge-nf-call-iptables
value: 1
state: present
- name: add Kubernetes' YUM repository
yum_repository:
name: Kubernetes
description: Kubernetes YUM repository
baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
gpgkey: https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
gpgcheck: yes
- name: install kubelet
yum:
name: kubelet
state: present
update_cache: true
- name: install kubeadm
yum:
name: kubeadm
state: present
- name: start kubelet
service:
name: kubelet
enabled: yes
state: started
- hosts: master
become: yes
tasks:
- name: install kubectl
yum:
name: kubectl
state: present
文件中的的第一部分内容如下:
sysctl
值。这将允许Kubernetes设置iptables规则,以便在节点上接收桥接的IPv4和IPv6网络流量。kubelet
和kubeadm
。第二部分意思是在主节点上设置一下kubectl
的任务。
完成后保存并关闭文件。
接下来,执行playbook
:
ansible-playbook -i hosts ~/kube-cluster/kube-dependencies.yml
完成后,您将看到类似于以下内容的输出:
PLAY [all] ****
TASK [Gathering Facts] ****
ok: [worker1]
ok: [worker2]
ok: [master]
TASK [install Docker] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [disable SELinux] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [disable SELinux on reboot] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [ensure net.bridge.bridge-nf-call-ip6tables is set to 1] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [ensure net.bridge.bridge-nf-call-iptables is set to 1] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [start Docker] ****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [add Kubernetes' YUM repository] *****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [install kubelet] *****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [install kubeadm] *****
changed: [master]
changed: [worker1]
changed: [worker2]
TASK [start kubelet] ****
changed: [master]
changed: [worker1]
changed: [worker2]
PLAY [master] *****
TASK [Gathering Facts] *****
ok: [master]
TASK [install kubectl] ******
ok: [master]
PLAY RECAP ****
master : ok=9 changed=5 unreachable=0 failed=0
worker1 : ok=7 changed=5 unreachable=0 failed=0
worker2 : ok=7 changed=5 unreachable=0 failed=0
执行后,Docker,kubeadm
和kubelet
将安装在所有远程服务。kubectl
不是必需组件,仅用于执行集群命令。但是我们建议您还是安装它,因为您将仅从主节点运行kubectl
命令。
现在安装了所有系统依赖项。让我们设置主节点并初始化集群。
在本节中,您将设置主节点。然而在创建配置之前,我们需要熟悉几个概念,如Pods和Pod 网络插件。
Kubernetes的基本调度单元称为“pods”。它可以把更高级别的抽象内容增加到容器化组件。一个pod一般包含一个或多个容器,这样可以保证它们一直位于主机上,并且可以共享资源。Kubernetes中的每个pod都被分配一个唯一的(在集群内的)IP地址这样就可以允许应用程序使用端口,而不会有冲突的风险。Pod可以定义一个卷,例如本地磁盘目录或网络磁盘,并将其暴露在pod中的一个容器之中。pod可以通过Kubernetes API手动管理,也可以委托给控制器来管理。
每个pod都有自己的IP地址,一个节点上的pod应该能够使用pod的IP访问另一个节点上的pod。单个节点上的容器可以通过本地接口轻松进行通信。然而,pod之间的通信更复杂,并且需要单独的网络组件,该组件可以透明地将流量从一个节点上的pod传送到另一个节点上的pod。此功能由pod网络插件提供。对于这个群集,建议您将使用Flannel选项。
在本地计算机上创建一个命名为master.yml
的Ansible playbook :
vi ~/kube-cluster/master.yml
将以下内容添加到文件中以初始化集群并安装Flannel:
- 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: centos
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/centos/.kube/config
remote_src: yes
owner: centos
- name: install Pod network
become: yes
become_user: centos
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
这是上面内容的详解:
kubeadm init
初始化集群。传递--pod-network-cidr=10.244.0.0/16
参数指定将从中分配pod IP的私有子网。Flannel默认使用上述子网,我们告诉kubeadm
使用相同的子网。.kube
目录在/home/centos
。此目录将保存配置信息,例如连接到群集所需的管理密钥文件以及群集的API地址。/etc/kubernetes/admin.conf
生成的文件复制kubeadm init
到centos用户的主目录。这将允许您用kubectl
访问新创建的群集。kubectl apply
安装Flannel
。kubectl apply -f descriptor.[yml|json]
是告诉kubectl
创建descriptor.[yml|json]
文件中描述的对象的语法。kube-flannel.yml
文件包含Flannel
在群集中设置所需的对象的说明。完成后保存并关闭文件。执行配置:
ansible-playbook -i hosts ~/kube-cluster/master.yml
完成后,您将看到类似于以下内容的输出:
PLAY [master] ****
TASK [Gathering Facts] ****
ok: [master]
TASK [initialize the cluster] ****
changed: [master]
TASK [create .kube directory] ****
changed: [master]
TASK [copy admin.conf to user's kube config] *****
changed: [master]
TASK [install Pod network] *****
changed: [master]
PLAY RECAP ****
master : ok=5 changed=4 unreachable=0 failed=0
要检查主节点的状态,请使用以下命令通过SSH连接到该节点:
ssh centos@master_ip
进入主节点后,执行:
kubectl get nodes
您现在将看到以下输出:
NAME STATUS ROLES AGE VERSION
master Ready master 1d v1.10.1
输出表明master
节点已完成所有初始化任务,并且处于Ready
可以开始接受工作节点并执行发送到API服务器的任务的状态。您现在可以从本地计算机添加工作程序。
将工作程序添加到集群涉及在每个集群上执行单个命令。此命令包括必要的群集信息,例如主服务器API服务器的IP地址和端口以及安全令牌。只有传入安全令牌的节点才能加入群集。
f反回您的工作区并创建一个名为workers.yml的配置:
vi ~/kube-cluster/workers.yml
将以下文本添加到文件中:
- 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
以下是配置的作用:
kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>
一旦它获得具有的令牌和哈希值的命令,该任务就将其设置为可用,以便下一个配置能够访问该信息。完成后保存并关闭文件。执行配置:
ansible-playbook -i hosts ~/kube-cluster/workers.yml
完成后,您将看到类似于以下内容的输出:
PLAY [master] ****
TASK [get join command] ****
changed: [master]
TASK [set join command] *****
ok: [master]
PLAY [workers] *****
TASK [Gathering Facts] *****
ok: [worker1]
ok: [worker2]
TASK [join cluster] *****
changed: [worker1]
changed: [worker2]
PLAY RECAP *****
master : ok=2 changed=1 unreachable=0 failed=0
worker1 : ok=2 changed=1 unreachable=0 failed=0
worker2 : ok=2 changed=1 unreachable=0 failed=0
通过添加工作节点,您的群集现在已完全设置并正常运行,工作节点可以随时运行工作负载。让我们验证群集是否按预期工作。
集群有时可能在安装过程中失败,因为节点已关闭或主服务器与工作服务器之间的网络连接无法正常工作。让我们验证集群并确保节点正常运行。
您需要从主节点检查群集的当前状态,以确保节点已准备就绪。如果从主节点断开连接,则可以使用以下命令通过SSH将其重新连接到主节点:
ssh centos@master_ip
然后执行以下命令以获取集群的状态:
kubectl get nodes
您将看到类似于以下内容的输出:
NAME STATUS ROLES AGE VERSION
master Ready master 1d v1.10.1
worker1 Ready <none> 1d v1.10.1
worker2 Ready <none> 1d v1.10.1
如果所有的节点都具有Ready
的STATUS
(状态),这意味着它们是集群的一部分,并准备运行工作负载。
但是,如果几个节点拥有NotReady
的STATUS
(状态),它可能意味着工作节点还没有完成自己的设置。等待大约五到十分钟再重新运行kubectl get node
并检查新输出。如果一些节点仍具有NotReady
状态,则需要验证并重新运行前面步骤中的命令。
现在您的集群已成功验证,让我们在集群上部署一个示例Nginx应用程序。
您现在可以将任何容器化应用程序部署到您的群集。让我们使用部署和服务部署Nginx,以了解如何将此应用程序部署到集群。如果更改Docker镜像名称和任何相关标志(例如ports
和volumes
),您也可以使用以下命令用于其他容器化应用程序。
在主节点内,执行以下命令以创建名为nginx的部署:
kubectl run nginx --image=nginx --port 80
部署是一种Kubernetes对象,可确保始终根据已定义的模板运行指定数量的pod,即使pod在群集生命周期内崩溃也是如此。上面的部署将使用Docker镜像库的Nginx Docker Image创建一个包含一个容器的pod 。
接下来,运行以下命令以创建名为nginx
将公开公共应用程序的服务。它将通过NodePort实现,该方案将通过在群集的每个节点上打开的任意端口访问pod:
kubectl expose deploy nginx --port 80 --target-port 80 --type NodePort
服务是另一种类型的Kubernetes对象,它向内部和外部客户端公开集群内部服务。它们还能够对多个pod进行负载均衡请求,并且是Kubernetes中不可或缺的组件,经常与其他组件交互。
运行以下命令:
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
从上面输出的第三行,您可以检索运行Nginx的端口。Kubernetes将分配一个大于30000
自动的随机端口,同时确保该端口尚未受到其他服务的约束。
要测试一切正常,请访问或通过本地计算机上的浏览器。您将看到Nginx熟悉的欢迎页面。http://worker_1_ip:nginx_port
或者http://worker_2_ip:nginx_port
。
如果要删除Nginx应用程序,请先nginx从主节点删除该服务:
kubectl delete service nginx
运行以下命令以确保已删除该服务:
kubectl get services
您将看到以下输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 1d
然后删除部署:
kubectl delete deployment nginx
运行以下命令以确认这是否有效:
kubectl get deployments
No resources found.
由于要用到谷歌的服务,所以要求您的网络环境可以访问外国网站,具体的方案就不在这里说了;
如下图所示,cent7是我们上一章操作完成后对应的CentOS7的VMware文件夹,现在把这个文件夹复制三份一模一样的,再分别重命名为maste、node1、node2:
打开VMware软件,选中上面我们复制的master文件夹,选中里面的文件然后点击“打开”按钮,如下图:
如下图,点击红框中的“编辑虚拟机设置”按钮
如下图,在设置页面中将虚拟机名字改成”master”:
如下图,点击红框中的按钮启动master:
如下图,在弹出的窗口中选择“我已复制该虚拟机”:
等master启动完毕,进入系统,修改/etc/hostname文件,这里面只有一行内容“localhost.localdomain”,改成”master”;
修改完hostname文件后,重启master;
执行以下命令设置kubelet自启动,然后再启动kubelet服务:
systemctl enable kubelet;systemctl start kubelet
执行以下命令,初始化kubernetes的master服务,此时由于要去下载谷歌服务的镜像文件,所以请保证当前网络可以访问外国网站:
kubeadm init --pod-network-cidr=192.168.0.0/16 --apiserver-advertise-address=0.0.0.0
如果网络没有问题,就请耐心等待吧,大约二十分钟就会完成init过程,如下图:
注意上图中的最后一句kubeadm join –token 4fccd2.b0e0f8918bd95d3e 192.168.119.132:6443,在node加入的时候我们就是用这一句来将node加入到集群的;
为什么init操作要用这么长时间呢?执行docker images命令可以看到下载多了很多镜像,如下图:
新增了6个镜像;
执行以下命令,把配置信息复制到执行目录中:
mkdir -p $HOME/.kube;cp -i /etc/kubernetes/admin.conf $HOME/.kube/config;chown $(id -u):$(id -g) $HOME/.kube/config
执行以下命令,安装Calico
kubectl apply -f http://docs.projectcalico.org/v2.4/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml
执行以下命令,看基础服务的pod都起来了没有:
kubectl get pods --all-namespaces
看到的pod信息如下图所示,红框中有一个pod并不是Running状态,而是ContainerCreating:
这时候请耐心等待几分钟,再看就会变成下面的状态:
用docker images命令看一下,发现多了几个镜像,如下图:
用kubectl get node命令查看当前的节点信息,能看见只有一个master节点,如下图:
至此,kubernetes集群的master节点就安装完成了