更新鏈接: https://github.com/mushuanli/wsue/wiki/Kubernetes-%E9%83%A8%E7%BD%B2
1. 介紹
1.1 docker介紹
docker 是kubertnetes的運(yùn)行基礎(chǔ)。在了解kubernetes前應(yīng)當(dāng)先了解docker.
1.1.1 介紹
軟件開(kāi)發(fā)會(huì)趨于復(fù)雜,帶來(lái)的最大的麻煩在于環(huán)境配置。特別是不同的應(yīng)用有不同的依賴(lài),當(dāng)軟件升級(jí)時(shí),依賴(lài)沖突經(jīng)常變成難以解決的問(wèn)題。
傳統(tǒng)解決環(huán)境配置的方法是針對(duì)不同應(yīng)用使用不同虛擬機(jī)部署,但是虛擬機(jī)耗費(fèi)資源,而且性能損失不小,同時(shí)啟動(dòng)慢。
另外一種方式就是使用名字空間和資源分組對(duì)應(yīng)用進(jìn)行隔離,使應(yīng)用運(yùn)行在自己的虛擬環(huán)境中(但是不會(huì)進(jìn)行整個(gè)系統(tǒng)的虛擬)。由于不需要進(jìn)行操作系統(tǒng)級(jí)別的虛擬化,僅進(jìn)行應(yīng)用運(yùn)行環(huán)境的隔離,優(yōu)點(diǎn)是資源占用小,啟動(dòng)快,性能損失少。這個(gè)典型的解決方案是docker。
[圖片上傳失敗...(image-c77651-1564578806788)]
同時(shí)由于docker封裝了應(yīng)用和運(yùn)行環(huán)境, 這個(gè)特點(diǎn)很適合把傳統(tǒng)應(yīng)用微服務(wù)化。微服務(wù)化可以使軟件實(shí)現(xiàn)彈性擴(kuò)展、快速迭代,促進(jìn)DevOps(DevOps 強(qiáng)調(diào)的是高效組織團(tuán)隊(duì)之間如何通過(guò)自動(dòng)化的工具協(xié)作和溝通來(lái)完成軟件的生命周期管理,從而更快、更頻繁地交付更穩(wěn)定的軟件。有工具支持,運(yùn)維關(guān)注代碼,開(kāi)發(fā)關(guān)注部署,效率和質(zhì)量都能得到提升。)
[圖片上傳失敗...(image-88aa46-1564578806788)]
1.1.2 docker 依賴(lài)技術(shù)
Docker中的容器化是通過(guò)依賴(lài)兩大技術(shù):
- 資源隔離(cgroups),內(nèi)核名稱(chēng)空間(隔離應(yīng)用程序的操作系統(tǒng)視圖,進(jìn)程樹(shù)等)
- 支持聯(lián)合的文件系統(tǒng)(例如aufs - 將多個(gè)目錄安裝到一個(gè)看似于包含它們的組合內(nèi)容)。
[圖片上傳失敗...(image-217cc0-1564578806789)]
1.1.3 docker 概念
docker 有3個(gè)核心概念:
鏡像(Image): 應(yīng)用程序映像。
鏡像是一個(gè)特殊的文件系統(tǒng),除了提供容器運(yùn)行時(shí)所需的程序、庫(kù)、資源、配置等文件外,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)(如匿名卷、環(huán)境變量、用戶(hù)等)。鏡像不包含任何動(dòng)態(tài)數(shù)據(jù),其內(nèi)容在構(gòu)建之后也不會(huì)被改變。容器(Container):正在運(yùn)行的Image。但是運(yùn)行的Image不會(huì)修改Image本身內(nèi)容,所有對(duì)Image的改動(dòng)在容器停止運(yùn)行后丟失,為了避免數(shù)據(jù)丟失可以在運(yùn)行時(shí)mount 本地目錄。
倉(cāng)庫(kù)(Docker registry): Docker 倉(cāng)庫(kù)是集中存放鏡像文件的場(chǎng)所。鏡像構(gòu)建完成后,可以很容易的在當(dāng)前宿主上運(yùn)行。
但是, 如果需要在其他服務(wù)器上使用這個(gè)鏡像,我們就需要一個(gè)集中的存儲(chǔ)、分發(fā)鏡像的服務(wù),Docker Registry(倉(cāng)庫(kù)注冊(cè)服務(wù)器)就是這樣的服務(wù)。
另外:
- Dockerfile: 聲明了Image 怎樣被創(chuàng)建的規(guī)則。
下面是他們的關(guān)系列表:
[圖片上傳失敗...(image-5604bb-1564578806789)]
容器和映像的文件系統(tǒng)關(guān)系如下:
容器在映像上面增加了一個(gè)可寫(xiě)層,但是每一次容器退出,這個(gè)可寫(xiě)層的內(nèi)容就丟失,所以容器每一次運(yùn)行文件系統(tǒng)都是相同的:
[圖片上傳失敗...(image-60546c-1564578806789)]
1.1.4 第一個(gè)例子: 在CentOS上運(yùn)行 Ubuntu
這個(gè)例子體現(xiàn)了docker作為輕量級(jí)虛擬機(jī)的特點(diǎn)(共用內(nèi)核,但是系統(tǒng)不一樣):
安裝Docker:
yum install -y docker
systemctl enable docker && systemctl start docker
用 docker pull ubuntu 把ubuntu下載到本地:
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
[root@localhost ~]# docker pull ubuntu
Using default tag: latest
Trying to pull repository docker.io/library/ubuntu ...
latest: Pulling from docker.io/library/ubuntu
6abc03819f3e: Pull complete
05731e63f211: Pull complete
0bd67c50d6be: Pull complete
Digest: sha256:f08638ec7ddc90065187e7eabdfac3c96e5ff0f6b2f1762cf31a4f49b53000a5
Status: Downloaded newer image for docker.io/ubuntu:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/ubuntu latest 7698f282e524 3 weeks ago 69.9 MB
docker images 看到ubuntu到鏡像僅 69MB 大小,這比起虛擬機(jī)來(lái)小太多了。而后面安裝應(yīng)用程序時(shí)僅添加應(yīng)用程序的依賴(lài),使得環(huán)境很簡(jiǎn)潔。
運(yùn)行ubuntu:
[root@localhost ~]# ls /home/
admin enable manager
[root@localhost ~]# docker run -it --rm -v /home/:/builddir ubuntu /bin/bash
root@90f65fac1f07:/# ls /builddir/
admin enable manager
root@1f610ad274b3:/# apt list
Listing... Done
adduser/now 3.116ubuntu1 all [installed,local]
apt/now 1.6.10 amd64 [installed,local]
base-files/now 10.1ubuntu2.4 amd64 [installed,local]
base-passwd/now 3.5.44 amd64 [installed,local]
bash/now 4.4.18-2ubuntu1 amd64 [installed,local]
......
另外啟動(dòng)一個(gè)終端,使用docker ps 可以看到容器已經(jīng)運(yùn)行, ifconfig 看到docker0網(wǎng)橋,和 veth 開(kāi)始的表示給容器使用的網(wǎng)卡, docker inspect 查看容器信息:
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b6f0b23e4077 ubuntu "/bin/bash" 14 seconds ago Up 13 seconds elated_minsky
[root@localhost ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.248.1 netmask 255.255.248.0 broadcast 0.0.0.0
ether 02:42:6d:d7:a8:44 txqueuelen 0 (Ethernet)
RX packets 54 bytes 3544 (3.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.206.138.103 netmask 255.255.252.0 broadcast 10.206.139.255
ether 00:0c:29:10:f5:82 txqueuelen 1000 (Ethernet)
RX packets 1313112 bytes 831831412 (793.2 MiB)
RX errors 0 dropped 40 overruns 0 frame 0
TX packets 436949 bytes 643904800 (614.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth9620c4e: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 86:46:62:9e:64:be txqueuelen 0 (Ethernet)
RX packets 13 bytes 1006 (1006.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2 bytes 140 (140.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost ~]# docker inspect b6f0b23e4077
[
{
"Id": "c6041b62d5426c4467687918ea5e741bd4cfb215dced172d750ff4b9b4520404",
"Created": "2019-06-09T03:35:06.651278353Z",
"Path": "/bin/bash",
......
docker run -it --rm -v /home/:/builddir ubuntu /bin/bash 意義:
- -i : interactive 交互模式, 可以輸入命令
- -t : tty 分配一個(gè)控制臺(tái)
- --rm: 當(dāng)容器退出時(shí)清除容器文件系統(tǒng)
- -v /home/:/builddir : 把本地的/home目錄映射到容器內(nèi)的 /builddir 目錄
- ubuntu: 鏡像名稱(chēng)
- /bin/bash: 容器啟動(dòng)的命令。
在容器中可以象在真實(shí)系統(tǒng)中一樣讀寫(xiě),但是僅在映射的目錄下的改動(dòng)才會(huì)保存。
按control-d 或是輸入 exit 退出 /bin/bash, 同時(shí)發(fā)現(xiàn)容器也退出了,docker ps 看不到容器信息。
上面就體驗(yàn)到容器就是應(yīng)用程序的執(zhí)行環(huán)境,當(dāng)應(yīng)用程序退出后容器也就退出了。
1.1.5 第二個(gè)例子: 啟動(dòng)nginx 服務(wù)
上面的例子體驗(yàn)了容器訪問(wèn)本地目錄功能
這個(gè)例子體驗(yàn)容器當(dāng)成服務(wù)器運(yùn)行功能, 體現(xiàn)了docker 作為服務(wù)器應(yīng)用的分發(fā)工具特色(一個(gè)鏡像就是應(yīng)用的完整運(yùn)行環(huán)境,即拉即用(pull and run))。
[root@localhost ~]# docker pull nginx
Using default tag: latest
Trying to pull repository docker.io/library/nginx ...
latest: Pulling from docker.io/library/nginx
743f2d6c1f65: Pull complete
d6c2f01b1dae: Pull complete
d4da6ff1b555: Pull complete
Digest: sha256:12db363acf5b2d2f9f5fed240e228a04692bdac68402430fbd2f720c3a967d01
Status: Downloaded newer image for docker.io/nginx:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/nginx latest 62c261073ecf 4 days ago 109 MB
docker.io/ubuntu latest 7698f282e524 3 weeks ago 69.9 MB
可見(jiàn)nginx 才109MB
下面是運(yùn)行,這次是后臺(tái)運(yùn)行,所以原來(lái)的 -it 不用(交互和控制臺(tái)),取代成 -d (守護(hù)模式)
同時(shí)加了 -p 8081:80 表示把本地的8081 tcp端口映射到 容器內(nèi)的 80 端口
最后使用 curl 訪問(wèn)了一下,發(fā)現(xiàn)訪問(wèn)成功。
[root@localhost ~]# docker run --name runoob-nginx-test -p 8081:80 -d nginx
384f1d5ad031306237e338f6e0e7e711f539dd12f48c9d136dfe760dc62ba721
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
384f1d5ad031 nginx "nginx -g 'daemon ..." 7 seconds ago Up 5 seconds 0.0.0.0:8081->80/tcp runoob-nginx-test
[root@localhost ~]# cu
curl cut
[root@localhost ~]# curl localhost:8081
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a >nginx.org</a>.<br/>
Commercial support is available at
<a >nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
運(yùn)行完后使用 docker kill 停止容器。
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
384f1d5ad031 nginx "nginx -g 'daemon ..." 3 minutes ago Up 3 minutes 0.0.0.0:8081->80/tcp runoob-nginx-test
[root@localhost ~]# docker kill 384f1d5ad031
384f1d5ad031
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1.1.6 docker 命令介紹
[圖片上傳失敗...(image-317d3c-1564578806789)]
1.1.7 構(gòu)建自己的鏡像
構(gòu)建自己的鏡像有多個(gè)方法,例如直接從 tar 包生成,
但是大部分鏡像都是繼承某個(gè)系統(tǒng),例如在ubuntu或是centos (因?yàn)榇蟛糠謶?yīng)用都是在某個(gè)系統(tǒng)上開(kāi)發(fā))
這時(shí)就使用dockerfile, 下面是它的一個(gè)例子:
Dockerfile文件格式如下:
## Dockerfile文件格式
# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# 1、第一行必須指定 基礎(chǔ)鏡像信息
FROM ubuntu
# 2、維護(hù)者信息
MAINTAINER docker_user docker_user@email.com
# 3、鏡像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# 4、容器啟動(dòng)執(zhí)行指令
CMD /usr/sbin/nginx
Dockerfile 分為四部分:基礎(chǔ)鏡像信息、維護(hù)者信息、鏡像操作指令、容器啟動(dòng)執(zhí)行指令。
- 一開(kāi)始必須要指明所基于的鏡像名稱(chēng),
- 接下來(lái)一般會(huì)說(shuō)明維護(hù)者信息;
- 后面則是鏡像操作指令,例如 RUN 指令。每執(zhí)行一條RUN 指令,鏡像添加新的一層,并提交;
- 最后是 CMD 指令,來(lái)指明運(yùn)行容器時(shí)的操作命令。
構(gòu)建
docker build -f /path/to/a/Dockerfile .
構(gòu)建好后 docker images 可以看到新建的鏡像.
1.2. kubernetes介紹
Kubernetes(k8s)是Google開(kāi)源的容器集群管理系統(tǒng)(谷歌內(nèi)部:Borg), 在Docker技術(shù)的基礎(chǔ)上,為容器化的應(yīng)用提供部署運(yùn)行、資源調(diào)度、服務(wù)發(fā)現(xiàn)和動(dòng)態(tài)伸縮等一系列完整功能,提高了大規(guī)模容器集群管理的便捷性。下面是他的主要功能:
[圖片上傳失敗...(image-f4cded-1564578806789)]
kubernetes的兩個(gè)設(shè)計(jì)理念依賴(lài):
docker。
它讓開(kāi)發(fā)者將自己的應(yīng)用以及依賴(lài)打包到一個(gè)可移植的容器中,讓?xiě)?yīng)用程序的運(yùn)行可以實(shí)現(xiàn)環(huán)境無(wú)關(guān)。docker是微服務(wù)良好的載體。微服務(wù)。
隨著軟件變得越來(lái)越復(fù)雜,一個(gè)完整的后端服務(wù)不再是單體服務(wù),而是由多個(gè)職責(zé)和功能不同的服務(wù)組成,服務(wù)之間復(fù)雜的拓?fù)潢P(guān)系以及單機(jī)已經(jīng)無(wú)法滿(mǎn)足的性能需求使得軟件的部署和運(yùn)維工作變得非常復(fù)雜,這也就使得部署和運(yùn)維大型集群變成了非常迫切的需求。微服務(wù)應(yīng)運(yùn)而生。
Kubernetes優(yōu)勢(shì):
- - 容器編排
- - 輕量級(jí)
- - 開(kāi)源
- - 彈性伸縮
- - 負(fù)載均衡
kubernetes架構(gòu),如下圖,由一個(gè)master和多個(gè)worker(也叫Node/Slave)組成, Master負(fù)責(zé)管理集群,提供集群的資源數(shù)據(jù)訪問(wèn)入口, Worker(Node/Slave)用來(lái)承載被分配Pod的運(yùn)行,是Pod運(yùn)行的宿主機(jī):
[圖片上傳失敗...(image-5002c3-1564578806789)]
內(nèi)部工作流程交互如下:
[圖片上傳失敗...(image-41c445-1564578806789)]
1.3. kubernetes關(guān)鍵概念
1.3.1. Master
k8s集群的管理節(jié)點(diǎn),負(fù)責(zé)管理集群,提供集群的資源數(shù)據(jù)訪問(wèn)入口。
[圖片上傳失敗...(image-a5980b-1564578806789)]
擁有Etcd存儲(chǔ)服務(wù)(可選),運(yùn)行Api Server進(jìn)程,Controller Manager服務(wù)進(jìn)程及Scheduler服務(wù)進(jìn)程,關(guān)聯(lián)工作節(jié)點(diǎn)Node。
Kubernetes API server提供HTTP Rest接口的關(guān)鍵服務(wù)進(jìn)程,是Kubernetes里所有資源的增、刪、改、查等操作的唯一入口。也是集群控制的入口進(jìn)程;
Kubernetes Controller Manager是Kubernetes所有資源對(duì)象的自動(dòng)化控制中心;
Kubernetes Schedule是負(fù)責(zé)資源調(diào)度(Pod調(diào)度)的進(jìn)程。
1.3.2. Node(Worker)
[圖片上傳失敗...(image-eba528-1564578806789)]
Node是Kubernetes集群操作的單元,用來(lái)承載被分配Pod的運(yùn)行,是Pod運(yùn)行的宿主機(jī)。關(guān)聯(lián)Master管理節(jié)點(diǎn),擁有名稱(chēng)和IP、系統(tǒng)資源信息。
運(yùn)行docker eninge服務(wù),守護(hù)進(jìn)程kunelet及負(fù)載均衡器kube-proxy.
每個(gè)Node節(jié)點(diǎn)都運(yùn)行著以下一組關(guān)鍵進(jìn)程
kubelet:負(fù)責(zé)對(duì)Pod對(duì)于的容器的創(chuàng)建、啟停等任務(wù)
kube-proxy:實(shí)現(xiàn)Kubernetes Service的通信與負(fù)載均衡機(jī)制的重要組件
Docker Engine(Docker):Docker引擎,負(fù)責(zé)本機(jī)容器的創(chuàng)建和管理工作。
1.3.3. POD
在Kubernetes中最小的部署單位。
[圖片上傳失敗...(image-62b464-1564578806789)]
Pod由一至多個(gè)容器所組成,而在一般應(yīng)用層面上由于下述幾點(diǎn)原因,使其較接近于一般使用的VM:
- 共享同樣的IP位址及Port space
同個(gè)Pod內(nèi)的容器可以透過(guò)localhost來(lái)互相溝通
Pod可以直接透過(guò)該IP和其他Pod進(jìn)行聯(lián)系,但一般而言我們會(huì)透過(guò)service來(lái)取代直接Pod存取
- 共享儲(chǔ)存空間(volumes)
- 耦合性較高之應(yīng)用,例如:
[圖片上傳失敗...(image-26dc45-1564578806789)]
為什么不直接在一個(gè)容器中運(yùn)行多個(gè)應(yīng)用程序呢?
- 透明。讓Pod中的容器對(duì)基礎(chǔ)設(shè)施可見(jiàn),以便基礎(chǔ)設(shè)施能夠?yàn)檫@些容器提供服務(wù),例如進(jìn)程管理和資源監(jiān)控。這可以為用戶(hù)帶來(lái)極大的便利。
- 解耦軟件依賴(lài)。每個(gè)容器都可以進(jìn)行版本管理,獨(dú)立的編譯和發(fā)布。未來(lái)kubernetes甚至可能支持單個(gè)容器的在線升級(jí)。
- 使用方便。用戶(hù)不必運(yùn)行自己的進(jìn)程管理器,還要擔(dān)心錯(cuò)誤信號(hào)傳播等。
- 效率。因?yàn)橛苫A(chǔ)架構(gòu)提供更多的職責(zé),所以容器可以變得更加輕量級(jí)。
1.3.4. Replication Controller/RS/Deployment
副本控制器(Replication Controller,RC)
用來(lái)管理Pod的副本,保證集群中存在指定數(shù)量的Pod副本。
集群中副本的數(shù)量大于指定數(shù)量,則會(huì)停止指定數(shù)量之外的多余容器數(shù)量,反之,則會(huì)啟動(dòng)少于指定數(shù)量個(gè)數(shù)的容器,保證數(shù)量不變。
Replication Controller是實(shí)現(xiàn)彈性伸縮、動(dòng)態(tài)擴(kuò)容和滾動(dòng)升級(jí)的核心。
副本集(Replica Set,RS)
RS是新一代RC,提供同樣的高可用能力,區(qū)別主要在于RS后來(lái)居上,能支持更多種類(lèi)的匹配模式。副本集對(duì)象一般不單獨(dú)使用,而是作為Deployment的理想狀態(tài)參數(shù)使用。
部署(Deployment)
部署表示用戶(hù)對(duì)Kubernetes集群的一次更新操作。部署是一個(gè)比RS應(yīng)用模式更廣的API對(duì)象,可以是創(chuàng)建一個(gè)新的服務(wù),更新一個(gè)新的服務(wù),也可以是滾動(dòng)升級(jí)一個(gè)服務(wù)。滾動(dòng)升級(jí)一個(gè)服務(wù),實(shí)際是創(chuàng)建一個(gè)新的RS,然后逐漸將新RS中副本數(shù)增加到理想狀態(tài),將舊RS中的副本數(shù)減小到0的復(fù)合操作;這樣一個(gè)復(fù)合操作用一個(gè)RS是不太好描述的,所以用一個(gè)更通用的Deployment來(lái)描述。以Kubernetes的發(fā)展方向,未來(lái)對(duì)所有長(zhǎng)期伺服型的的業(yè)務(wù)的管理,都會(huì)通過(guò)Deployment來(lái)管理。
有狀態(tài)服務(wù)集(StatefulSet)
RC和RS主要是控制提供無(wú)狀態(tài)服務(wù)的,其所控制的Pod的名字是隨機(jī)設(shè)置的,一個(gè)Pod出故障了就被丟棄掉,在另一個(gè)地方重啟一個(gè)新的Pod,名字變了。名字和啟動(dòng)在哪兒都不重要,重要的只是Pod總數(shù);
而StatefulSet是用來(lái)控制有狀態(tài)服務(wù),StatefulSet中的每個(gè)Pod的名字都是事先確定的,不能更改。
對(duì)于RC和RS中的Pod,一般不掛載存儲(chǔ)或者掛載共享存儲(chǔ),保存的是所有Pod共享的狀態(tài),Pod像牲畜一樣沒(méi)有分別(這似乎也確實(shí)意味著失去了人性特征);
對(duì)于StatefulSet中的Pod,每個(gè)Pod掛載自己獨(dú)立的存儲(chǔ),如果一個(gè)Pod出現(xiàn)故障,從其他節(jié)點(diǎn)啟動(dòng)一個(gè)同樣名字的Pod,要掛載上原來(lái)Pod的存儲(chǔ)繼續(xù)以它的狀態(tài)提供服務(wù)。
1.3.5. service
Kubernetes Service是個(gè)抽象化的概念,主要定義了邏輯上的一群Pod(帶著相同標(biāo)簽、做類(lèi)似事情的一群Pod)以及如何存取他們的規(guī)則。
Service作為中介層,避免使用者和Pod進(jìn)行直接聯(lián)機(jī),除了讓我們服務(wù)維持一定彈性能夠選擇不同的Pod來(lái)處理請(qǐng)求外,某種程度上亦避免裸露無(wú)謂的Port而導(dǎo)致信息安全問(wèn)題。
對(duì)于使用者而言,僅須知道有人會(huì)處理他們的請(qǐng)求,而毋須知道實(shí)際上處理的人是誰(shuí)。
[圖片上傳失敗...(image-2a66e8-1564578806789)]
關(guān)于Service相關(guān)IP:
Pod IP:每個(gè)pod 都有獨(dú)立的虛擬IP, 通過(guò)網(wǎng)絡(luò)插件創(chuàng)建IP(如flannel),使跨主機(jī)的Pod可以互通Cluster IP:是Service的內(nèi)部IP,可以看成一個(gè)域名解析,解析最后發(fā)給哪個(gè)POD,可以用做內(nèi)部POD訪問(wèn)服務(wù)。通過(guò)iptables規(guī)則訪問(wèn)服務(wù)。External IP: 是Service的外部IP,對(duì)外提供給Client訪問(wèn)。
Pod IP 和 Cluster IP 都是kubernetes內(nèi)部ip。
1.3.6. Label
Kubernetes中的任意API對(duì)象都是通過(guò)Label進(jìn)行標(biāo)識(shí),Label的實(shí)質(zhì)是一系列的Key/Value鍵值對(duì),其中key于value由用戶(hù)自己指定。
Label可以附加在各種資源對(duì)象上,如Node、Pod、Service、RC等,一個(gè)資源對(duì)象可以定義任意數(shù)量的Label,同一個(gè)Label也可以被添加到任意數(shù)量的資源對(duì)象上去。
Label是Replication Controller和Service運(yùn)行的基礎(chǔ),二者通過(guò)Label來(lái)進(jìn)行關(guān)聯(lián)Node上運(yùn)行的Pod。
1.3.7. 存儲(chǔ)卷(Volume)
Kubernetes集群中的存儲(chǔ)卷跟Docker的存儲(chǔ)卷有些類(lèi)似,只不過(guò)Docker的存儲(chǔ)卷作用范圍為一個(gè)容器,而Kubernetes的存儲(chǔ)卷的生命周期和作用范圍是一個(gè)Pod。每個(gè)Pod中聲明的存儲(chǔ)卷由Pod中的所有容器共享。
Kubernetes支持非常多的存儲(chǔ)卷類(lèi)型,特別的,支持多種公有云平臺(tái)的存儲(chǔ),包括AWS,Google和Azure云;
支持多種分布式存儲(chǔ)包括GlusterFS和Ceph;也支持較容易使用的主機(jī)本地目錄emptyDir, hostPath和NFS。
Kubernetes還支持使用Persistent Volume Claim即PVC這種邏輯存儲(chǔ),使用這種存儲(chǔ),使得存儲(chǔ)的使用者可以忽略后臺(tái)的實(shí)際存儲(chǔ)技術(shù)(例如AWS,Google或GlusterFS和Ceph),而將有關(guān)存儲(chǔ)實(shí)際技術(shù)的配置交給存儲(chǔ)管理員通過(guò)Persistent Volume來(lái)配置。
持久存儲(chǔ)卷(Persistent Volume,PV)和持久存儲(chǔ)卷聲明(Persistent Volume Claim,PVC
PV和PVC使得Kubernetes集群具備了存儲(chǔ)的邏輯抽象能力,使得在配置Pod的邏輯里可以忽略對(duì)實(shí)際后臺(tái)存儲(chǔ)技術(shù)的配置,而把這項(xiàng)配置的工作交給PV的配置者,即集群的管理者。
存儲(chǔ)的PV和PVC的這種關(guān)系,跟計(jì)算的Node和Pod的關(guān)系是非常類(lèi)似的;
PV和Node是資源的提供者,根據(jù)集群的基礎(chǔ)設(shè)施變化而變化,由Kubernetes集群管理員配置;
而PVC和Pod是資源的使用者,根據(jù)業(yè)務(wù)服務(wù)的需求變化而變化,有Kubernetes集群的使用者即服務(wù)的管理員來(lái)配置。
1.4. 使用yaml描述對(duì)象
1.4.1 YAML語(yǔ)法
kubernetes使用YAML寫(xiě)對(duì)象信息, YAML語(yǔ)法規(guī)則:
- 大小寫(xiě)敏感
- 使用縮進(jìn)表示層級(jí)關(guān)系
- 縮進(jìn)時(shí)不允許使用Tal鍵,只允許使用空格
- 縮進(jìn)的空格數(shù)目不重要,只要相同層級(jí)的元素左側(cè)對(duì)齊即可
- ”#” 表示注釋?zhuān)瑥倪@個(gè)字符一直到行尾,都會(huì)被解析器忽略
1.4.2 Pod, Service和Deployment
Kubernetes有三個(gè)你應(yīng)該知道的對(duì)象類(lèi)型:
- Pods - 運(yùn)行一個(gè)或多個(gè)密切相關(guān)的容器
- Service - 在Kubernetes集群中建立網(wǎng)絡(luò)
- Deployment - 維護(hù)一組相同的pod,確保它們具有正確的配置并且存在正確的數(shù)量。
Pod:
- 運(yùn)行一組容器
- 適合一次性開(kāi)發(fā)目的
- 很少直接用于生產(chǎn)
Deployment:
- 運(yùn)行一組相同的pod
- 監(jiān)視每個(gè)pod的狀態(tài),并根據(jù)需要進(jìn)行更新
- 對(duì)開(kāi)發(fā)者有好處
- 適合生產(chǎn)
盡量避免使用Pod并實(shí)施Deployments來(lái)管理容器作為類(lèi)型的對(duì)象
Pod在節(jié)點(diǎn)故障或pod終止時(shí)不會(huì)被重新安排(或自我修復(fù))。
1.4.3. 使用yaml描述對(duì)象
在 Kubernetes 系統(tǒng)中,Kubernetes 對(duì)象 是持久化的實(shí)體。Kubernetes 使用這些實(shí)體去表示整個(gè)集群的狀態(tài)。特別地,它們描述了如下信息:
- 哪些容器化應(yīng)用在運(yùn)行(以及在哪個(gè) Node 上)
- 可以被應(yīng)用使用的資源
- 關(guān)于應(yīng)用運(yùn)行時(shí)表現(xiàn)的策略,比如重啟策略、升級(jí)策略,以及容錯(cuò)策略
可以簡(jiǎn)單的分類(lèi)為以下幾種資源對(duì)象:
| 類(lèi)別 | 名稱(chēng) |
|---|---|
| 資源對(duì)象 | Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、 Job、CronJob、 HorizontalPodAutoscaling、Node、Namespace、Service、 Ingress、Label、CustomResourceDefinition |
| 存儲(chǔ)對(duì)象 | Volume、PersistentVolume、Secret、ConfigMap |
| 策略對(duì)象 | SecurityContext、ResourceQuota、LimitRange |
| 身份對(duì)象 | ServiceAccount、Role、ClusterRole |
大多數(shù)情況下,需要在 .yaml 文件中為 kubectl 提供對(duì)象信息。
在想要?jiǎng)?chuàng)建的 Kubernetes 對(duì)象對(duì)應(yīng)的 .yaml 文件中,需要配置如下的字段:
- apiVersion - 創(chuàng)建該對(duì)象所使用的 Kubernetes API 的版本
- kind - 想要?jiǎng)?chuàng)建的對(duì)象的類(lèi)型
- metadata - 幫助識(shí)別對(duì)象唯一性的數(shù)據(jù),包括一個(gè) name 字符串、UID 和可選的 namespace
這里有更多例子:
https://cheatsheet.dennyzhang.com/kubernetes-yaml-templates
下面是一些常用例子:
- Endpoints
可以把外部的鏈接到k8s系統(tǒng)中,如下將一個(gè)mysql連接到k8s中。
kind: Endpoints
apiVersion: v1
metadata:
name: mysql-production
namespace: test
subsets:
- addresses:
- ip: 10.0.0.82 # 外部mysql ip
ports:
- port: 3306 # 外部mysql 端口
- service
apiVersion: v1
kind: Service
metadata:
name: mysql-production
namespace: test
spec:
ports:
- port: 3306
# port: 3306為內(nèi)部IP
name: mysql-production #為service名稱(chēng)
# 此時(shí)mysql-production.test即為mysql的虛擬IP,其他可配置該字段連接到mysql,例如
# "java","-Dspring.datasource.url=jdbc:mysql://mysql-production.test:3306/config", "-jar", "xxx.jar"
1.4.2. pod配置例子
apiVersion: v1 #指定api版本,此值必須在kubectl apiversion中
kind: Pod #指定創(chuàng)建資源的角色/類(lèi)型
metadata: #資源的元數(shù)據(jù)/屬性
name: web04-pod #資源的名字,在同一個(gè)namespace中必須唯一
labels: #設(shè)定資源的標(biāo)簽,詳情請(qǐng)見(jiàn)http://blog.csdn.net/liyingke112/article/details/77482384
k8s-app: apache
version: v1
kubernetes.io/cluster-service: "true"
annotations: #自定義注解列表
- name: String #自定義注解名字
spec:#specification of the resource content 指定該資源的內(nèi)容
restartPolicy: Always #表明該容器一直運(yùn)行,默認(rèn)k8s的策略,在此容器退出后,會(huì)立即創(chuàng)建一個(gè)相同的容器
nodeSelector: #節(jié)點(diǎn)選擇,先給主機(jī)打標(biāo)簽kubectl label nodes kube-node1 zone=node1
zone: node1
containers:
- name: web04-pod #容器的名字
image: web:apache #容器使用的鏡像地址
imagePullPolicy: Never #三個(gè)選擇Always、Never、IfNotPresent,每次啟動(dòng)時(shí)檢查和更新(從registery)images的策略,
# Always,每次都檢查
# Never,每次都不檢查(不管本地是否有)
# IfNotPresent,如果本地有就不檢查,如果沒(méi)有就拉取
command: ['sh'] #啟動(dòng)容器的運(yùn)行命令,將覆蓋容器中的Entrypoint,對(duì)應(yīng)Dockefile中的ENTRYPOINT
args: ["$(str)"] #啟動(dòng)容器的命令參數(shù),對(duì)應(yīng)Dockerfile中CMD參數(shù)
env: #指定容器中的環(huán)境變量
- name: str #變量的名字
value: "/etc/run.sh" #變量的值
resources: #資源管理,請(qǐng)求請(qǐng)見(jiàn)http://blog.csdn.net/liyingke112/article/details/77452630
requests: #容器運(yùn)行時(shí),最低資源需求,也就是說(shuō)最少需要多少資源容器才能正常運(yùn)行
cpu: 0.1 #CPU資源(核數(shù)),兩種方式,浮點(diǎn)數(shù)或者是整數(shù)+m,0.1=100m,最少值為0.001核(1m)
memory: 32Mi #內(nèi)存使用量
limits: #資源限制
cpu: 0.5
memory: 32Mi
ports:
- containerPort: 80 #容器開(kāi)發(fā)對(duì)外的端口
name: httpd #名稱(chēng)
protocol: TCP
livenessProbe: #pod內(nèi)容器健康檢查的設(shè)置,詳情請(qǐng)見(jiàn)http://blog.csdn.net/liyingke112/article/details/77531584
httpGet: #通過(guò)httpget檢查健康,返回200-399之間,則認(rèn)為容器正常
path: / #URI地址
port: 80
#host: 127.0.0.1 #主機(jī)地址
scheme: HTTP
initialDelaySeconds: 180 #表明第一次檢測(cè)在容器啟動(dòng)后多長(zhǎng)時(shí)間后開(kāi)始
timeoutSeconds: 5 #檢測(cè)的超時(shí)時(shí)間
periodSeconds: 15 #檢查間隔時(shí)間
#也可以用這種方法
#exec: 執(zhí)行命令的方法進(jìn)行監(jiān)測(cè),如果其退出碼不為0,則認(rèn)為容器正常
# command:
# - cat
# - /tmp/health
#也可以用這種方法
#tcpSocket: //通過(guò)tcpSocket檢查健康
# port: number
lifecycle: #生命周期管理
postStart: #容器運(yùn)行之前運(yùn)行的任務(wù)
exec:
command:
- 'sh'
- 'yum upgrade -y'
preStop: #容器關(guān)閉之前運(yùn)行的任務(wù)
exec:
command: ['service httpd stop']
volumeMounts: #詳情請(qǐng)見(jiàn)http://blog.csdn.net/liyingke112/article/details/76577520
- name: volume #掛載設(shè)備的名字,與volumes[*].name 需要對(duì)應(yīng)
mountPath: /data #掛載到容器的某個(gè)路徑下
readOnly: True
volumes: #定義一組掛載設(shè)備
- name: volume #定義一個(gè)掛載設(shè)備的名字
#meptyDir: {}
hostPath:
path: /opt #掛載設(shè)備類(lèi)型為hostPath,路徑為宿主機(jī)下的/opt,這里設(shè)備類(lèi)型支持很多種
1.4.3. deployment
部署一個(gè)Pod,內(nèi)部只能鏈接service,無(wú)法互相鏈接.
apiVersion: extensions/v1beta1 #接口版本
kind: Deployment #接口類(lèi)型
metadata:
name: cango-demo #Deployment名稱(chēng)
namespace: cango-prd #命名空間
labels:
app: cango-demo #標(biāo)簽
spec:
replicas: 3
strategy:
rollingUpdate: ##由于replicas為3,則整個(gè)升級(jí),pod個(gè)數(shù)在2-4個(gè)之間
maxSurge: 1 #滾動(dòng)升級(jí)時(shí)會(huì)先啟動(dòng)1個(gè)pod
maxUnavailable: 1 #滾動(dòng)升級(jí)時(shí)允許的最大Unavailable的pod個(gè)數(shù)
template:
metadata:
labels:
app: cango-demo #模板名稱(chēng)必填
sepc: #定義容器模板,該模板可以包含多個(gè)容器
containers:
- name: cango-demo #鏡像名稱(chēng)
image: swr.cn-east-2.myhuaweicloud.com/cango-prd/cango-demo:0.0.1-SNAPSHOT #鏡像地址
command: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ] #啟動(dòng)命令
args: #啟動(dòng)參數(shù)
- '-storage.local.retention=$(STORAGE_RETENTION)'
- '-storage.local.memory-chunks=$(STORAGE_MEMORY_CHUNKS)'
- '-config.file=/etc/prometheus/prometheus.yml'
- '-alertmanager.url=http://alertmanager:9093/alertmanager'
- '-web.external-url=$(EXTERNAL_URL)'
#如果command和args均沒(méi)有寫(xiě),那么用Docker默認(rèn)的配置。
#如果command寫(xiě)了,但args沒(méi)有寫(xiě),那么Docker默認(rèn)的配置會(huì)被忽略而且僅僅執(zhí)行.yaml文件的command(不帶任何參數(shù)的)。
#如果command沒(méi)寫(xiě),但args寫(xiě)了,那么Docker默認(rèn)配置的ENTRYPOINT的命令行會(huì)被執(zhí)行,但是調(diào)用的參數(shù)是.yaml中的args。
#如果如果command和args都寫(xiě)了,那么Docker默認(rèn)的配置被忽略,使用.yaml的配置。
imagePullPolicy: IfNotPresent #如果不存在則拉取
livenessProbe: #表示container是否處于live狀態(tài)。如果LivenessProbe失敗,LivenessProbe將會(huì)通知kubelet對(duì)應(yīng)的container不健康了。隨后kubelet將kill掉container,并根據(jù)RestarPolicy進(jìn)行進(jìn)一步的操作。默認(rèn)情況下LivenessProbe在第一次檢測(cè)之前初始化值為Success,如果container沒(méi)有提供LivenessProbe,則也認(rèn)為是Success;
httpGet:
path: /health #如果沒(méi)有心跳檢測(cè)接口就為/
port: 8080
scheme: HTTP
initialDelaySeconds: 60 ##啟動(dòng)后延時(shí)多久開(kāi)始運(yùn)行檢測(cè)
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /health #如果沒(méi)有心跳檢測(cè)接口就為/
port: 8080
scheme: HTTP
initialDelaySeconds: 30 ##啟動(dòng)后延時(shí)多久開(kāi)始運(yùn)行檢測(cè)
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
resources: ##CPU內(nèi)存限制
requests:
cpu: 2
memory: 2048Mi
limits:
cpu: 2
memory: 2048Mi
env: ##通過(guò)環(huán)境變量的方式,直接傳遞pod=自定義Linux OS環(huán)境變量
- name: LOCAL_KEY #本地Key
value: value
- name: CONFIG_MAP_KEY #局策略可使用configMap的配置Key,
valueFrom:
configMapKeyRef:
name: special-config #configmap中找到name為special-config
key: special.type #找到name為special-config里data下的key
ports:
- name: http
containerPort: 8080 #對(duì)service暴露端口
volumeMounts: #掛載volumes中定義的磁盤(pán)
- name: log-cache
mount: /tmp/log
- name: sdb #普通用法,該卷跟隨容器銷(xiāo)毀,掛載一個(gè)目錄
mountPath: /data/media
- name: nfs-client-root #直接掛載硬盤(pán)方法,如掛載下面的nfs目錄到/mnt/nfs
mountPath: /mnt/nfs
- name: example-volume-config #高級(jí)用法第1種,將ConfigMap的log-script,backup-script分別掛載到/etc/config目錄下的一個(gè)相對(duì)路徑path/to/...下,如果存在同名文件,直接覆蓋。
mountPath: /etc/config
- name: rbd-pvc #高級(jí)用法第2中,掛載PVC(PresistentVolumeClaim)
#使用volume將ConfigMap作為文件或目錄直接掛載,其中每一個(gè)key-value鍵值對(duì)都會(huì)生成一個(gè)文件,key為文件名,value為內(nèi)容,
volumes: # 定義磁盤(pán)給上面volumeMounts掛載
- name: log-cache
emptyDir: {}
- name: sdb #掛載宿主機(jī)上面的目錄
hostPath:
path: /any/path/it/will/be/replaced
- name: example-volume-config # 供ConfigMap文件內(nèi)容到指定路徑使用
configMap:
name: example-volume-config #ConfigMap中名稱(chēng)
items:
- key: log-script #ConfigMap中的Key
path: path/to/log-script #指定目錄下的一個(gè)相對(duì)路徑path/to/log-script
- key: backup-script #ConfigMap中的Key
path: path/to/backup-script #指定目錄下的一個(gè)相對(duì)路徑path/to/backup-script
- name: nfs-client-root #供掛載NFS存儲(chǔ)類(lèi)型
nfs:
server: 10.42.0.55 #NFS服務(wù)器地址
path: /opt/public #showmount -e 看一下路徑
- name: rbd-pvc #掛載PVC磁盤(pán)
persistentVolumeClaim:
claimName: rbd-pvc1 #掛載已經(jīng)申請(qǐng)的pvc磁盤(pán)
1.4.4. Service
部署一個(gè)內(nèi)部虛擬IP,其他deployment可以鏈接。
apiVersion: v1
kind: Service
matadata: #元數(shù)據(jù)
name: string #service的名稱(chēng)
namespace: string #命名空間
labels: #自定義標(biāo)簽屬性列表
- name: string
annotations: #自定義注解屬性列表
- name: string
spec: #詳細(xì)描述
selector: [] #label selector配置,將選擇具有l(wèi)abel標(biāo)簽的Pod作為管理
#范圍
type: string #service的類(lèi)型,指定service的訪問(wèn)方式,默認(rèn)為
#clusterIp
clusterIP: string #虛擬服務(wù)地址
sessionAffinity: string #是否支持session
ports: #service需要暴露的端口列表
- name: string #端口名稱(chēng)
protocol: string #端口協(xié)議,支持TCP和UDP,默認(rèn)TCP
port: int #服務(wù)監(jiān)聽(tīng)的端口號(hào)
targetPort: int #需要轉(zhuǎn)發(fā)到后端Pod的端口號(hào)
nodePort: int #當(dāng)type = NodePort時(shí),指定映射到物理機(jī)的端口號(hào)
status: #當(dāng)spce.type=LoadBalancer時(shí),設(shè)置外部負(fù)載均衡器的地址
loadBalancer: #外部負(fù)載均衡器
ingress: #外部負(fù)載均衡器
ip: string #外部負(fù)載均衡器的Ip地址值
hostname: string #外部負(fù)載均衡器的主機(jī)
1.4.5. ingress
你可以給Ingress配置提供外部可訪問(wèn)的URL、負(fù)載均衡、SSL、基于名稱(chēng)的虛擬主機(jī)等。用戶(hù)通過(guò)POST Ingress資源到API server的方式來(lái)請(qǐng)求ingress。 Ingress controller負(fù)責(zé)實(shí)現(xiàn)Ingress,通常使用負(fù)載平衡器,它還可以配置邊界路由和其他前端,這有助于以HA方式處理流量。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec: # Ingress spec 中包含配置一個(gè)loadbalancer或proxy server
rules: # 的所有信息。最重要的是,它包含了一個(gè)匹配所有入站請(qǐng)求的規(guī)
- http: # 則列表。目前ingress只支持http規(guī)則。
paths:
- path: /testpath # 每條http規(guī)則包含以下信息:一個(gè)host配置項(xiàng)(比如
# for.bar.com,在這個(gè)例子中默認(rèn)是*),path列表(比
# 如:/testpath),每個(gè)path都關(guān)聯(lián)一個(gè)backend(比如
# test:80)。在loadbalancer將流量轉(zhuǎn)發(fā)到backend之前,所有的
# 入站請(qǐng)求都要先匹配host和path。
backend:
serviceName: test # backend是一個(gè)service:port的組合。Ingress的流量被轉(zhuǎn)發(fā)到
servicePort: 80 # 它所匹配的backend
1.5. kubernetes其他功能介紹
configmaps: 為了讓?xiě)?yīng)用程序可以方便轉(zhuǎn)移或避免重新編譯image,因此會(huì)將配置與應(yīng)用程序解構(gòu),以單獨(dú)的ConfigMap配置.
永久性存儲(chǔ)Persistent Volume: Pod 里面指定mountPath和 type.
1.6. kubernetes第三方工具
Jaeger是一個(gè)開(kāi)源的分布式跟蹤Trace系統(tǒng),可以用來(lái)trace每個(gè)客戶(hù)端送出的請(qǐng)求,進(jìn)而找出執(zhí)行過(guò)程的問(wèn)題.
Helm是一個(gè)可以安裝與管理Kubernetes應(yīng)用程序的工具,我們可以將Helm視為是Kubernetes的package manager.
普羅米修斯(Prometheus)是一個(gè)可以提供Kubernetes應(yīng)用程序測(cè)量的開(kāi)源套件,一方面可以匯整測(cè)量信息,也可以提供警告(Alert)通知.
Deployment通常是首選,因?yàn)樗x了ReplicaSet以確保所需數(shù)量的Pod始終可用,并指定替換Pod的策略,例如RollingUpdate。
1.7. kubernetes網(wǎng)絡(luò)
Kubernetes本身并不提供網(wǎng)絡(luò)功能,只是把網(wǎng)絡(luò)接口開(kāi)放出來(lái),通過(guò)插件的形式實(shí)現(xiàn)。
Kubernetes中的網(wǎng)絡(luò)要解決的核心問(wèn)題就是每臺(tái)主機(jī)的IP地址網(wǎng)段劃分,以及單個(gè)容器的IP地址分配。概括為:
- 保證每個(gè)Pod擁有一個(gè)集群內(nèi)唯一的IP地址
- 保證不同節(jié)點(diǎn)的IP地址劃分不會(huì)重復(fù)
- 保證跨節(jié)點(diǎn)的Pod可以互相通信
- 保證不同節(jié)點(diǎn)的Pod可以與跨節(jié)點(diǎn)的主機(jī)互相通信
為了解決該問(wèn)題,出現(xiàn)了一系列開(kāi)源的Kubernetes中的網(wǎng)絡(luò)插件與方案,如:
- flannel
- calico
- contiv
- weave net
- kube-router
- cilium
- canal
[圖片上傳失敗...(image-d50565-1564578806789)]
1.7.1. flannel網(wǎng)絡(luò)
Flannel是作為一個(gè)二進(jìn)制文件的方式部署在每個(gè)node上,主要實(shí)現(xiàn)兩個(gè)功能:
- 為每個(gè)node分配subnet,容器將自動(dòng)從該子網(wǎng)中獲取IP地址
- 當(dāng)有node加入到網(wǎng)絡(luò)中時(shí),為每個(gè)node增加路由配置
下面是flannel網(wǎng)絡(luò)的運(yùn)行模式:
[圖片上傳失敗...(image-6afe01-1564578806789)]
Flannel首先創(chuàng)建了一個(gè)名為flannel0的網(wǎng)橋,而且這個(gè)網(wǎng)橋的一端連接docker0的網(wǎng)橋,另一端連接一個(gè)名為flanneld的服務(wù)進(jìn)程。
Flanneld進(jìn)程并不簡(jiǎn)單,它首先上連etcd,利用etcd來(lái)管理可分配的IP地址段資源,同時(shí)監(jiān)控etcd中每個(gè)Pod的實(shí)際地址,并在內(nèi)存中建立了一個(gè)Pod節(jié)點(diǎn)路由表;然后下連docker0和物理網(wǎng)絡(luò),使用內(nèi)存中的Pod節(jié)點(diǎn)路由表,將docker0發(fā)給它的數(shù)據(jù)包包裝起來(lái),利用物理網(wǎng)絡(luò)的連接將數(shù)據(jù)包投遞到目標(biāo)flanneld上,從而完成pod到pod之間的直接的地址通信。
Flannel之間的底層通信協(xié)議的可選余地有很多,比如UDP、VXlan、AWS VPC等等。只要能通到對(duì)端的Flannel就可以了。源Flannel封包,目標(biāo)Flannel解包,最終docker0看到的就是原始的數(shù)據(jù),非常透明,根本感覺(jué)不到中間Flannel的存在。
- 數(shù)據(jù)從源容器中發(fā)出后,經(jīng)由所在主機(jī)的docker0虛擬網(wǎng)卡轉(zhuǎn)發(fā)到flannel0虛擬網(wǎng)卡,這是個(gè)P2P的虛擬網(wǎng)卡,flanneld服務(wù)監(jiān)聽(tīng)在網(wǎng)卡的另外一端。
- Flannel通過(guò)Etcd服務(wù)維護(hù)了一張節(jié)點(diǎn)間的路由表。
- 源主機(jī)的flanneld服務(wù)將原本的數(shù)據(jù)內(nèi)容UDP封裝后根據(jù)自己的路由表投遞給目的節(jié)點(diǎn)的flanneld服務(wù),數(shù)據(jù)到達(dá)以后被解包,然后直接進(jìn)入目的節(jié)點(diǎn)的flannel0虛擬網(wǎng)卡,
然后被轉(zhuǎn)發(fā)到目的主機(jī)的docker0虛擬網(wǎng)卡,最后就像本機(jī)容器通信一下的有docker0路由到達(dá)目標(biāo)容器。
總結(jié):
- 基于 UDP 的 flannel 網(wǎng)絡(luò)模型具有簡(jiǎn)單易用,不依賴(lài)底層網(wǎng)絡(luò)的特點(diǎn)
- 性能和時(shí)延問(wèn)題。
Flannel實(shí)現(xiàn)了對(duì)Kubernetes網(wǎng)絡(luò)的支持,但是它引入了多個(gè)網(wǎng)絡(luò)組件,在網(wǎng)絡(luò)通信時(shí)需要轉(zhuǎn)到flannel0網(wǎng)絡(luò)接口,再轉(zhuǎn)到用戶(hù)態(tài)的flanneld程序,到對(duì)端后還需要走這個(gè)過(guò)程的反過(guò)程,所以也會(huì)引入一些網(wǎng)絡(luò)的時(shí)延損耗。另外Flannel默認(rèn)的底層通信協(xié)議是UDP。UDP本身是非可靠協(xié)議,雖然兩端的TCP實(shí)現(xiàn)了可靠傳輸,但在大流量、高并發(fā)應(yīng)用場(chǎng)景下還需要反復(fù)調(diào)試,確保不會(huì)出現(xiàn)傳輸質(zhì)量的問(wèn)題。特別是對(duì)網(wǎng)絡(luò)依賴(lài)重的應(yīng)用,需要評(píng)估對(duì)業(yè)務(wù)的影響。
- 性能和時(shí)延問(wèn)題。
1.7.2. Calico
Calico創(chuàng)建和管理一個(gè)扁平的三層網(wǎng)絡(luò)(不需要overlay),每個(gè)容器會(huì)分配一個(gè)可路由的IP。由于通信時(shí)不需要解包和封包,網(wǎng)絡(luò)性能損耗小,易于排查,且易于水平擴(kuò)展。
小規(guī)模部署時(shí)可以通過(guò)BGP client直接互聯(lián),大規(guī)模下可通過(guò)指定的BGP Route Reflector來(lái)完成,這樣保證所有的數(shù)據(jù)流量都是通過(guò)IP路由的方式完成互聯(lián)的。
Calico基于iptables還提供了豐富而靈活的網(wǎng)絡(luò)Policy,保證通過(guò)各個(gè)節(jié)點(diǎn)上的ACL來(lái)提供Workload的多租戶(hù)隔離、安全組以及其他可達(dá)性限制等功能。
[圖片上傳失敗...(image-2dd999-1564578806789)]
Calico主要由Felix、etcd、BGP client、BGP Route Reflector組成。
- Etcd:負(fù)責(zé)存儲(chǔ)網(wǎng)絡(luò)信息
- BGP client:負(fù)責(zé)將Felix配置的路由信息分發(fā)到其他節(jié)點(diǎn)
- Felix:Calico Agent,每個(gè)節(jié)點(diǎn)都需要運(yùn)行,主要負(fù)責(zé)配置路由、配置ACLs、報(bào)告狀態(tài)
- BGP Route Reflector:大規(guī)模部署時(shí)需要用到,作為BGP client的中心連接點(diǎn),可以避免每個(gè)節(jié)點(diǎn)互聯(lián)
1.8. 云上的kubernetes
在 Kubernetes 出現(xiàn)之前,就已經(jīng)有人提出了云原生的概念,如 2010 年 Paul Fremantle 就在他的博客中提出了云原生的核心理念,但是還沒(méi)有切實(shí)的技術(shù)解決方案。
而那時(shí)候 PaaS 才剛剛出現(xiàn),PaaS 平臺(tái)提供商 Heroku 提出了 12 因素應(yīng)用的理念,為構(gòu)建 SaaS 應(yīng)用提供了方法論,該理念在云原生時(shí)代依然適用。
現(xiàn)如今云已經(jīng)可以為我們提供穩(wěn)定而唾手可得的基礎(chǔ)設(shè)施,但是業(yè)務(wù)上云成了一個(gè)難題,Kubernetes 的出現(xiàn)與其說(shuō)是從最初的容器編排解決方案開(kāi)始,倒不如說(shuō)是為了解決應(yīng)用上云(即云原生應(yīng)用)這個(gè)難題。
Kubernetes 作為云應(yīng)用的部署標(biāo)準(zhǔn),直接面向業(yè)務(wù)應(yīng)用,大大提高了云應(yīng)用的可移植性,解決云廠商鎖定的問(wèn)題,讓云應(yīng)用可以在夸云之間無(wú)縫遷移,甚至用來(lái)管理混合云,成為企業(yè) IT 云平臺(tái)的新標(biāo)準(zhǔn)。
1.8.1 AKS 介紹
微軟的Azure Kubernetes Service以下簡(jiǎn)稱(chēng)AKS,提供簡(jiǎn)單的部署,管理與操作界面,具有以下的幾個(gè)特點(diǎn):
- 訂閱者不必?fù)?dān)心升級(jí)與修正問(wèn)題,AKS提供自動(dòng)更新與修正
- AKS服務(wù)具有高可用度與高可靠性
- AKS可以透過(guò)命令或UI簡(jiǎn)單的調(diào)整擴(kuò)充
- AKS具有自我修復(fù)能力
- AKS提供API Server監(jiān)控機(jī)制
- AKS可以透過(guò)Azure AD以及Role Base Access Control(RBAC)控管叢集的存取安全性
- AKS服務(wù)的Azure托管的管理控制平臺(tái)(Control plane/Master nodes)提供免費(fèi)使用
這邊要特別說(shuō)明,AKS管理控制平臺(tái)是由微軟托管的,訂閱者不需要設(shè)定Master nodes,訂閱的使用者透過(guò)Kubernetes API endpoint,使用命令(Azure Cli - az aks)來(lái)管理AKS.
[圖片上傳失敗...(image-29c9fc-1564578806789)]
2. Centos7安裝
安裝可以分成3個(gè)部分:
配置系統(tǒng)參數(shù),例如使用不同的hostname , 禁止swap和 selinux,允許防火墻通過(guò)某些端口等等
在所有節(jié)點(diǎn)上安裝docker
在所有節(jié)點(diǎn)上安裝kubernetes
配置主節(jié)點(diǎn)
在worker節(jié)點(diǎn)上向主節(jié)點(diǎn)注冊(cè)自己。
下面將分別介紹。
2.1. 配置系統(tǒng)參數(shù)
2.1.1. 每個(gè)機(jī)器使用不同的主機(jī)名
在每臺(tái)機(jī)器上運(yùn)行:
hostnamectl set-hostname new-hostname
如果沒(méi)有自己的 DNS 服務(wù)器,那么需要修改所有機(jī)器的 /etc/hosts 文件,把kuberntes內(nèi)所有主機(jī)名(master 和 worker node )和ip的對(duì)應(yīng)添加進(jìn)來(lái), 例如:
192.168.1.30 k8s-master
192.168.1.40 worker-node1
192.168.1.50 worker-node2
2.1.2. 關(guān)閉selinux
setenforce 0 #實(shí)時(shí)動(dòng)態(tài)關(guān)閉 selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config #禁止重啟后自動(dòng)開(kāi)啟
2.1.3. 關(guān)閉swap
swapoff -a #實(shí)時(shí)動(dòng)態(tài)關(guān)閉交換分區(qū)
sed -i '/ swap / s/^/#/' /etc/fstab #禁止重啟后自動(dòng)開(kāi)啟
2.1.4. 配置網(wǎng)絡(luò)防火墻
簡(jiǎn)單一些的辦法是直接禁止:
systemctl disable firewalld && systemctl stop firewalld
復(fù)雜點(diǎn)是開(kāi)放 kubernetes 需要的端口,下面是master node:
firewall-cmd --permanent --add-port=6443/tcp
firewall-cmd --permanent --add-port=2379-2380/tcp
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=10251/tcp
firewall-cmd --permanent --add-port=10252/tcp
firewall-cmd --permanent --add-port=10255/tcp
firewall-cmd --reload
worker node:
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=10255/tcp
firewall-cmd --permanent --add-port=30000-32767/tcp
firewall-cmd --permanent --add-port=6783/tcp
firewall-cmd --reload
2.1.5. 配置網(wǎng)絡(luò)參數(shù)
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
vm.swappiness=0
EOF
modprobe br_netfilter #執(zhí)行該命令 如果不執(zhí)行就會(huì)在應(yīng)用k8s.conf時(shí)出現(xiàn)加載錯(cuò)誤
sysctl -p /etc/sysctl.d/k8s.conf #應(yīng)用配置文件
2.2. 安裝docker
kuberntes 使用docker作為pod 的運(yùn)行基礎(chǔ)。 CentOS7.6 自帶的 docker 是支持kubernetes的。通過(guò)下面命令安裝。
sudo yum install -y docker
sudo systemctl enable docker && sudo systemctl start docker
如果需要也可以使用最新的 docker-ce:
2.3. 安裝kubernetes
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
yum install -y kubelet kubeadm kubectl
systemctl enable kubelet && systemctl start kubelet
如果上不了谷歌,那么根據(jù)這個(gè)下載image和yum安裝
# https://blog.csdn.net/jb19900111/article/details/88884848
[root@k8smaster ~]# cat getk8s_images.sh
#!/bin/bash
images=(
kube-apiserver:v1.14.0
kube-controller-manager:v1.14.0
kube-scheduler:v1.14.0
kube-proxy:v1.14.0
pause:3.1
etcd:3.3.10
coredns:1.3.1
kubernetes-dashboard-amd64:v1.10.0
heapster-amd64:v1.5.4
heapster-grafana-amd64:v5.0.4
heapster-influxdb-amd64:v1.5.2
pause-amd64:3.1
)
for imageName in ${images[@]} ; do
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
done
[root@k8smaster ~]# sh -x getk8s_images.sh
[root@k8smaster ~]# cat /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
[root@k8smaster ~]# yum -y install kubelet kubeadm kubectl --disableexcludes=kubernetes
2.4. 配置主節(jié)點(diǎn)(master node)
確認(rèn)一下docker 已經(jīng)使用 systemd:
docker info | grep -i cgroup
會(huì)顯示 "Cgroup Driver: systemd", 如果不是那需要修改
在master節(jié)點(diǎn)上運(yùn)行:
kubeadm init --apiserver-advertise-address=192.168.1.30 --pod-network-cidr=10.244.0.0/16
其中:
--apiserver-advertise-address 指定master 節(jié)點(diǎn)的ip地址。如果 master 節(jié)點(diǎn)只有一個(gè)ip, 可以忽略這個(gè)參數(shù)。
--pod-network-cidr=10.244.0.0/16 指定pod網(wǎng)絡(luò)地址范圍, 10.244.0.0/16 是 flannel 網(wǎng)絡(luò)的IP地址范圍,如果想使用其他網(wǎng)絡(luò)類(lèi)型,那么根據(jù)它的介紹設(shè)置參數(shù)。
命令執(zhí)行后會(huì)有提示,根據(jù)提示執(zhí)行:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
還有安裝網(wǎng)絡(luò)的提示:
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml
OK, 現(xiàn)在 master 安裝好了。
上面命令還有一個(gè)重要提示,就是worker node注冊(cè)命令, 把這個(gè)命令保存下來(lái)備用:
sudo kubeadm join 192.168.0.120:6443 --token khm95w.mo0wwenu2o9hglls \
--discovery-token-ca-cert-hash sha256:aeb0ca593b63c8d674719858fd2397825825cebc552e3c165f00edb9671d6e32
可以選裝 dashboard, master 上執(zhí)行下面安裝:
#kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
2.5. 工作節(jié)點(diǎn)(worker node)注冊(cè)
在worker node 執(zhí)行上面"kubeadm init "產(chǎn)生的注冊(cè)命令,就可以成功添加worker node到 master node:
sudo kubeadm join 192.168.0.120:6443 --token khm95w.mo0wwenu2o9hglls \
--discovery-token-ca-cert-hash sha256:aeb0ca593b63c8d674719858fd2397825825cebc552e3c165f00edb9671d6e32
2.6. 驗(yàn)證和調(diào)試
所有的kubernetes 狀態(tài)和配置都可以通過(guò) kubectl獲取,但是這個(gè)命令僅能在master node上執(zhí)行。
2.6.1. 查看狀態(tài)
下面查看狀態(tài):
kubectl get nodes
kubectl get pods --all-namespaces
2.6.2. 創(chuàng)建一個(gè)pod和服務(wù)
創(chuàng)建pod 和服務(wù)有兩種方法:
直接kubectl 命令行創(chuàng)建
在yaml 里面定義,然后調(diào)用 kubectl apply -f 創(chuàng)建
下面是命令行創(chuàng)建方法:
[root@k8smaster ~]# kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
[root@k8smaster ~]# kubectl describe deployment nginx
Name: nginx
Namespace: default
CreationTimestamp: Fri, 07 Jun 2019 23:24:06 -0400
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx
Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available False MinimumReplicasUnavailable
Progressing True ReplicaSetUpdated
OldReplicaSets: <none>
NewReplicaSet: nginx-65f88748fd (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 10s deployment-controller Scaled up replica set nginx-65f88748fd to 1
[root@k8smaster ~]# kubectl create service nodeport nginx --tcp=80:80
service/nginx created
[root@k8smaster ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-65f88748fd-kjjdk 1/1 Running 0 44s
[root@k8smaster ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 39h
nginx NodePort 10.109.182.154 <none> 80:32303/TCP 13s
訪問(wèn)新建的service:
[root@k8smaster ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 39h
nginx NodePort 10.109.182.154 <none> 80:32303/TCP 13s
[root@k8smaster ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8smaster Ready master 39h v1.14.2
k8snode1 Ready <none> 39h v1.14.2
[root@k8smaster ~]# curl k8snode1:32303
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a >nginx.org</a>.<br/>
Commercial support is available at
<a >nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
還可以訪問(wèn) master node/ 或是 svr 運(yùn)行的 worker node 的 svr 開(kāi)放端口:
附nginx 的service 和 deployment 編寫(xiě)方法,
通過(guò)
kubectl create -f nginx.yaml
創(chuàng)建
通過(guò):
kubectl delete -f nginx.yaml
刪除
[root@k8smaster ~]# cat nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ports:
- port: 8000 # the port that this service should serve on
# the container on each pod to connect to, can be a name
# (e.g. 'www') or a number (e.g. 80)
targetPort: 80
protocol: TCP
# just like the selector in the deployment,
# but this time it identifies the set of pods to load balance
# traffic to.
selector:
app: nginx
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: 10.206.138.106:5000/nginx:latest
resources:
limits:
memory: "128Mi"
cpu: "250m"
ports:
- containerPort: 80
imagePullSecrets:
- name: vmireposec