《精通Docker第三版》完整目录:
第一章 Docker概览
第二章 创建容器镜像
第三章 存储和发布镜像
第四章 管理容器
第五章 Docker Compose
第六章 Windows容器
第七章 Docker Machine
第八章 Docker Swarm
第九章 Docker和Kubernetes
第十章 在公有云上运行Docker
第十一章 Portainer – 一个Docker的GUI
第十二章 Docker安全
第十三章 Docker工作流
第十四章 Docker进阶
本章中,我们一起来看Kubernetes。和Docker Swarm相似,我们可以使用Kubernetes来创建和管理用于运行基于容器的应用集群。
本章涵盖的主要内容有:
Kubernetes的介绍
启动Kubernetes
使用Kubernetes
Kubernetes和其它Docker工具
技术准备
Docker中的Kubernetes只支由Docker for Mac和Docker for Windows支持。和此前章节一样,作者将使用自己偏好的操作系统macOS。同样,其中极少数据的支持命令可能只在macOS中使用。
观看如下视频来查看代码的实时操作:
VIDEO
Kubernetes简介
如果你有了解容器,那么总会在某个地方碰到Kubernetes,在Docker桌面软件中启动它之前,我们先花点时间了解下Kubernetes的前世今身。
Kubernetes(音koo-ber-net-eez)来自给予舵手或船长的希腊名称。Kubernetes(也称为K8s),是一个起源于Google的开源项目,允许我们自动化部署、管理和扩容容器化应用。
Google的容器简史
Google对于Linux容器解决方案的研究历时已久。2016年迈出了第一步,开发Linux内核称作控制组(cgroups)的功能。这一功能于2008年合并到了Linux发行版2.6.24的内核中。该功能让我们可以隔离资源,如CPU、RAM、网络和磁盘I/O,或一个或多个进程。控制组仍然是Linux容器的核心组成并为Docker及其它容器工具所使用。
Google接着以名为lmctfy的容器栈涉足容器领域,它是Let Me Contain That For You的缩写。这是LXC的工具集和库的一个替代。这是 Google 内部在自己应用内用于管理容器的工具的一个开源版本。
译者注: LXC 表示 Linux Container,即 Linux 容器。
接着Google再次成为容器使用新闻热点是在2014年5月的Gluecon上Joe Beda进行讲话之后 。在讲话期间,Beda透露Google当时几乎所有业务都基于容器,以及他们每周会启动近20亿个容器。并声称这一数字并不包含长期运行的容器,也就是说这些容器都是供短期使用的。但是进行快速的数学计算之后,这表示Google平均每秒会启动3000个容器。
在讲话的后半段,Beda提及Google使用了调度器这样他们无需每周手动管理20亿个容器,或担心容器在哪里启动乃至容器的可用性。
Google还发布了一篇名为Large-scale cluster management at Google with Borg(Google 使用 Borg 进行大规模集群的管理)的论文。该论文不仅让Google以外的人知道了他们使用的调度器的名称,Borg,还深入到了在设计调度器时做设计决策的细节。
该论文也提到了他们的内部工具,Google在容器运行集群中运行面向用户的应用,如 Google Docs、Gmail和Google 搜索,都是由Borg进行管理。
Borg使用电视节目星际迷航:下一代 的外星种族Borg来进行命名。在电视节目中,Borg是一种半机械生物,它们的文明基于称为“集合体”的集体意识。这使他们不仅可以共享相同的想法,同时通过子空间网络,确保每个集合体的成员透过集体意识给予指导和监督。相信你也会同意,Borg种族的特征与我们希望运行的容器集群匹配度极高。
Borg在Google内部使用了好几年,最终由名为Omega的调试器替代。大约是这个时候Google声明会拿出一些Borg的核心功能,将其重塑为一个开源项目。这个项目内部称之为Seven,由多名Borg的核心贡献人员操刀。目标在于创建一个版本更为友好的Borg,脱离Google自己的内部流程和工作方式。
Seven,取名自星际迷航:航海家号 中的人物,九之七(Seven of Nine)是从集合体中解放出来的博格个体,最终在首次对外提交时使用了Kubernetes这一名称。
Kubernetes概览
那么,现在我们知道了Kubernetes的由来,可以更深入的挖掘Kubernetes是什么了。该项目的大部分,确切地说是88.5%,由 Go 语言编写,这不足为奇,因为Go在2011年开源之前是由Google内部开发的一种编程语言。此项目的其它部分文件由Python和Shell帮助脚本和HTML文档组成。
一个典型的Kubernetes集群由角色为master或node服务器组成。你可以对这两种角色的节点进行单独安装。
master角色是神奇发生的地方,同时也是集群的大脑。它负责决定在何处启动pod,并且监控集群本身以及集群内运行的pod的健康状况。我们在了解了这两个角色之后会来讨论pod。
通常,核心组件会部署到角色分配为master的主机上:
kube-apiserver:这个组件暴露主Kubernetes API。它设计为横向扩展,这表示你可以持续添加更多的实例来让集群保持高可用。
etcd:这是一个高可用一致性键值存储。用于存储集群的状态。
kube-scheduler:这个组件负责决定pod在哪里启动。
kube-controller-manager:这一组件运行控制器。这些控制器在Kubernetes中有多个功能,如监控节点,监测应用、管理端点(endpoint)以及生成服务账号和令牌。
cloud-controller-manager:这一组件管理处个控制器,与第三方去进行交互来启动和配置支持服务。
上面讲解了管理组件,下面需要讨论它们所管理的内容是什么。node由如下组件构成:
kubelet:这个代理(agent)运行在集群内的node上,它是管理节点与node进行交互的方式。也负责管理各个pod。
kube-proxy::这个组件管理所有的请求路由以及node和pod的通讯。
container runtime:可以是Docker RKT或任意遵循OCI(Oracle Call Interface)的运行时。
你可能注意到了到此我们没提到容器。这是因为Kubernetes实际上不直接与容器进行交互,它与pod进行通讯。把pod看作一个完整的应用,有点像我们使用Docker Compose启动多个容器的应用。
Kubernetes和Docker
Kubernetes最早被视作Docker自己的集群技术Docker Swarm的竞品。但通过这几年的发展,Kubernetes实际上已成为容器编排的标准了。
所有主流云提供商都提供Kubernetes即服务。有如下这些:
谷歌云: Google Kubernetes引擎(GKE)
Microsoft Azure: Azure Kubernetes服务(AKS)
Amazon Web Services: Amazon的Kubernetes弹性容器服务 (EKS)
IBM: IBM云Kubernetes服务
甲骨文云: Oracle的Kubernetes容器引擎
DigitalOcean: DigitalOcean上的Kubernetes
表面上,所有这些主流玩家支持Kubernetes可能并没有什么了不起的。但别忘了我们可以在跨多平台部署容器化应用并保持一致性。以前,这些平台被称作后花园,与它们交互的方式非常的不同。
在Docker在2017年10月初次发表声明时普遍表示惊讶,但尘埃落定时又是那么的理所当然。使用Docker for Mac和Docker for Windows为开发人员提供可以在本地操作应用,然后使用Docker企业版来部署和管理自己的Kubernetes集群,甚至是使用前述的一种云服务,与我们在第一章 Docker概览 中讨论的“像在本机操作”非常契合。
下面我们来看如何在Docker软件中启动Kubernetes支持并进一步的进行使用。
启动Kubernetes
Docker上Kubernetes的安装过程极为简单。启动Kubernetes支持,我们只需要打开Preferences并点击Kubernetes选项卡:
可以看到,有三个主选项。勾选Enable Kubernetes复选框,然后选择Deploy Docker Stacks to Kubernetes by default。先不勾选Show systems containers,我们会在启动服务后再来看更多的细节。点击Apply会弹出如下信息:
点击Install按钮会下载所需的容器来在Docker软件上启动Kubernetes的支持:
像前面的一个对话框中所提示的那样,Docker会需要不些时间来进行下载、配置和启动该集群。完成后,你会看到Kubernetes is running旁边有绿点:
打开Terminal并运行如下命令:
正常运行后不会显示任何容器。运行如下命令:
这会列出Kubernetes相关的镜像:
k8s . gcr . io /kube -proxy -amd64
k8s . gcr . io /kube -apiserver -amd64
k8s . gcr . io /kube -controller -manager -amd64
k8s . gcr . io /kube -scheduler -amd64
docker /kube -compose -controller
docker /kube -compose -api -server
k8s . gcr . io /etcd -amd64
k8s . gcr . io /k8s -dns -dnsmasq -nanny -amd64
k8s . gcr . io /k8s -dns -sidecar -amd64
k8s . gcr . io /k8s -dns -kube -dns -amd64
k8s . gcr . io /pause -amd64
这些镜像的源为Docker和Google容器仓库(k8s.gcr.io)所提供的官方Kubernetes。
你可能已经猜到,勾选Show system containers (advanced)复选框,然后运行以下命令会列出在本地Docker软件上启动Kubernetes服务所有运行的容器:
因为运行上述命令会有大量输出,以下仅显示容器的名称。通过运行如下命令来进行实现:
$ docker container ls --format { { . Names } }
运行该命令会得到如下输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ docker container ls --format { { . Names } }
k8s_compose_compose -74649b4db6 -j4t8r_docker_184e337c -658d -11e9 -9fe6 -025000000001_0
k8s_compose_compose -api -79c95fc7d6 -gbkq4_docker_18464718 -658d -11e9 -9fe6 -025000000001_0
k8s_POD_compose -74649b4db6 -j4t8r_docker_184e337c -658d -11e9 -9fe6 -025000000001_0
k8s_POD_compose -api -79c95fc7d6 -gbkq4_docker_18464718 -658d -11e9 -9fe6 -025000000001_0
k8s_sidecar_kube -dns -86f4d74b45 -mjtp8_kube -system_f0ce645a -658c -11e9 -9fe6 -025000000001_0
k8s_dnsmasq_kube -dns -86f4d74b45 -mjtp8_kube -system_f0ce645a -658c -11e9 -9fe6 -025000000001_0
k8s_kubedns_kube -dns -86f4d74b45 -mjtp8_kube -system_f0ce645a -658c -11e9 -9fe6 -025000000001_0
k8s_kube -proxy_kube -proxy -jsf94_kube -system_f0c7ceb6 -658c -11e9 -9fe6 -025000000001_0
k8s_POD_kube -dns -86f4d74b45 -mjtp8_kube -system_f0ce645a -658c -11e9 -9fe6 -025000000001_0
k8s_POD_kube -proxy -jsf94_kube -system_f0c7ceb6 -658c -11e9 -9fe6 -025000000001_0
k8s_kube -scheduler_kube -scheduler -docker -for -desktop_kube -system_ecf299f4fa454da5ab299dffcd70c70f_0
k8s_kube -apiserver_kube -apiserver -docker -for -desktop_kube -system_7fbb107871a3c31e9b65e5e5aa8427e9_0
k8s_kube -controller -manager_kube -controller -manager -docker -for -desktop_kube -system_5fd9f57b2e532f401708dfe8a8bcc3c2_0
k8s_etcd_etcd -docker -for -desktop_kube -system_37c1035b2a8313813aad96455cd61937_0
k8s_POD_kube -scheduler -docker -for -desktop_kube -system_ecf299f4fa454da5ab299dffcd70c70f_0
k8s_POD_kube -controller -manager -docker -for -desktop_kube -system_5fd9f57b2e532f401708dfe8a8bcc3c2_0
k8s_POD_kube -apiserver -docker -for -desktop_kube -system_7fbb107871a3c31e9b65e5e5aa8427e9_0
k8s_POD_etcd -docker -for -desktop_kube -system_37c1035b2a8313813aad96455cd61937_0
有18个运行中的容器,这也是存在隐藏它们的原因。可以看到几乎所有我们在前一部分讨论的组件以及其它一些提供Docker集成的组件。我会推荐不勾选Show system containers的选项,因为我们不需要在每次查看运行中的容器时看到这18个容器。
这里另一件需要注意的事情是Kubernetes的菜单项中有内容了。这一菜单可用于在Kubernetes集群间进行切换。因为当前我们只有一个活跃的集群,因此只列出了一个:
现在我们本地的Kubernetes已启动并运行,下面就开始使用它吧。
使用Kubernetes
我们已经在Docker桌面软件上启动和运行了Kubernetes集群,可以开始与其进行交互了。先来看与Docker桌面组件一起安装的命令kubectl。
前面已提到,kubectl同时进行了安装。如下命令会显示客户端及其所连接到的集群的相关信息:
$ kubectl version
Client Version : version . Info { Major : "1" , Minor : "12" , GitVersion : "v1.12.2" , GitCommit : "17c77c7898218073f14c8d573582e8d2313dc740" , GitTreeState : "clean" , BuildDate : "2018-11-26T13:25:32Z" , GoVersion : "go1.11.2" , Compiler : "gc" , Platform : "darwin/amd64" }
Server Version : version . Info { Major : "1" , Minor : "10" , GitVersion : "v1.10.11" , GitCommit : "637c7e288581ee40ab4ca210618a89a555b6e7e9" , GitTreeState : "clean" , BuildDate : "2018-11-26T14:25:46Z" , GoVersion : "go1.9.3" , Compiler : "gc" , Platform : "linux/amd64" }
接下来运行如下命令来看kubectl是否能识别到我们的node:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
docker -for -desktop Ready master 1h v1 . 10.11
既然我们已经有了与node进行交互的客户端,就可以通过运行如下命令来查看在Kubernetes中默认配置的命名空间:
然后通过如下命令来在命名空间中查看pod:
$ kubectl get --namespace kube -system pods
$ kubectl get namespaces
NAME STATUS AGE
default Active 1h
docker Active 1h
kube -public Active 1h
kube -system Active 1h
$ kubectl get --namespace kube -system pods
NAME READY STATUS RESTARTS AGE
etcd -docker -for -desktop 1 /1 Running 0 1h
kube -apiserver -docker -for -desktop 1 /1 Running 0 1h
kube -controller -manager -docker -for -desktop 1 /1 Running 0 1h
kube -dns -86f4d74b45 -mjtp8 3 /3 Running 0 1h
kube -proxy -jsf94 1 /1 Running 0 1h
kube -scheduler -docker -for -desktop 1 /1 Running 0 1h
Kubernetes中的命名空间是集群内隔离资源的一种很好的方式。可以在Terminal的输出中看到,集群内有四个命名空间。有default命名空间,通常为空。两个主Kubernetes服务的命名空间:docker和kube-system。这些包含组成我们集群的pod以及最后一个命名空间,kube-public,类似default,为空。
在我们启动自己的pod之前,先快速地查看下如何与我们运行的pod进行交互,首先了解如何查找我们pod的更多信息:
$ kubectl describe --namespace kube -system pods kube -scheduler -docker -for -desktop
以上命令会打印出kube-scheduler-docker-for-desktop这一pod的明细信息。你可能注意到我们需要使用–namespace 来传递命名空间。如果不传递,那么kubectl会默认使用没有名为kube-scheduler-docker-for-desktop在运行的default命名空间。
该命令的完整输出如下所示:
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
Name : kube -scheduler -docker -for -desktop
Namespace : kube -system
Node : docker -for -desktop /192.168.65.3
Start Time : Tue , 23 Apr 2019 15 : 00 : 43 +0800
Labels : component =kube -scheduler
tier =control -plane
Annotations : kubernetes . io /config . hash : ecf299f4fa454da5ab299dffcd70c70f
kubernetes . io /config . mirror : ecf299f4fa454da5ab299dffcd70c70f
kubernetes . io /config . seen : 2019 -04 -23T05 : 56 : 03.9921627Z
kubernetes . io /config . source : file
scheduler . alpha . kubernetes . io /critical -pod :
Status : Running
IP : 192.168.65.3
Containers :
kube -scheduler :
Container ID : docker : //ceb5a8dbb3b984f785d0c96a98e41a662b2dfb2eb52fb241bf3edd62a98ed717
Image : k8s . gcr . io /kube -scheduler -amd64 : v1 . 10.11
Image ID : docker -pullable : //k8s.gcr.io/kube-scheduler-amd64@sha256:3f40a5beec15fe39300d5bac56d6d7b72957afca51d3353aeb77a563f889973c
Port : < none >
Host Port : < none >
Command :
kube -scheduler
--leader -elect =true
--kubeconfig =/etc /kubernetes /scheduler . conf
--address =127.0.0.1
State : Running
Started : Tue , 23 Apr 2019 15 : 00 : 44 +0800
Ready : True
Restart Count : 0
Requests :
cpu : 100m
Liveness : http -get http : //127.0.0.1:10251/healthz delay=15s timeout=15s period=10s #success=1 #failure=8
Environment : < none >
Mounts :
/etc /kubernetes /scheduler . conf from kubeconfig ( ro )
Conditions :
Type Status
Initialized True
Ready True
PodScheduled True
Volumes :
kubeconfig :
Type : HostPath ( bare host directory volume )
Path : /etc /kubernetes /scheduler . conf
HostPathType : FileOrCreate
QoS Class : Burstable
Node -Selectors : < none >
Tolerations : : NoExecute
Events : < none >
可以看到有关这一pod的大量信息,包含容器列表,我们只有一个,名为kube-scheduler。我们还可以看到镜像所使用的容器ID,容器启动使用的标记,以及Kubernetes调度器用于启动和维护该pod的数据。
我们已经知道了容器名,可以开始与其进行交互。例如,运行如下命令会打印出我们这一容器的日志:
$ kubectl logs --namespace kube -system kube -scheduler -docker -for -desktop -c kube -scheduler
W0423 07 : 00 : 44.837759 1 server . go : 163 ] WARNING : all flags other than --config are deprecated . Please begin using a config file ASAP .
I0423 07 : 00 : 44.844505 1 server . go : 555 ] Version : v1 . 10.11
I0423 07 : 00 : 44.844928 1 server . go : 574 ] starting healthz server on 127.0.0.1 : 10251
E0423 07 : 00 : 51.126897 1 reflector . go : 205 ] k8s . io /kubernetes /cmd /kube -scheduler /app /server . go : 594 : Failed to list * v1 . Pod : pods is forbidden : User "system:kube-scheduler" cannot list pods at the cluster scope
E0423 07 : 00 : 51.127282 1 reflector . go : 205 ] k8s . io /kubernetes /vendor /k8s . io /client -go /informers /factory . go : 87 : Failed to list * v1 . StorageClass : storageclasses . storage . k8s . io is forbidden : User "system:kube-scheduler" cannot list storageclasses . storage . k8s . io at the cluster scope
E0423 07 : 00 : 51.140152 1 reflector . go : 205 ] k8s . io /kubernetes /vendor /k8s . io /client -go /informers /factory . go : 87 : Failed to list * v1beta1 . ReplicaSet : replicasets . extensions is forbidden : User "system:kube-scheduler" cannot list replicasets . extensions at the cluster scope
. . .
运行如下命令会获取pod中的每个容器的日志:
$ kubectl logs --namespace kube -system kube -scheduler -docker -for -desktop
类似Docker,你还可以对pod和容器执行命令。例如,如下命令会运行uname -a 命令:
小贴士: 确保在如下两个命令的 — 后添加空格。不加的话会产生报错。
$ kubectl exec --namespace kube -system kube -scheduler -docker -for -desktop -c kube -scheduler -- uname -a
$ kubectl exec --namespace kube -system kube -scheduler -docker -for -desktop -- uname -a
同样,我们可以对指定名称的容器或pod中的所有容器运行该命令:
$ kubectl exec --namespace kube -system kube -scheduler -docker -for -desktop -c kube -scheduler -- uname -a
Linux linuxkit -025000000001 4.9.125 -linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 GNU/Linux
我们再来通过安装和向基于 web 的仪表盘记录日志来进一步了解Kubernetes。虽然Docker默认并不包含,通过Kubernetes项目提供的定义文件来安装非常之简单。我们只需要运行如下命令:
$ kubectl create -f https : //raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml
secret /kubernetes -dashboard -certs created
secret /kubernetes -dashboard -csrf created
serviceaccount /kubernetes -dashboard created
role . rbac . authorization . k8s . io /kubernetes -dashboard -minimal created
rolebinding . rbac . authorization . k8s . io /kubernetes -dashboard -minimal created
deployment . apps /kubernetes -dashboard created
service /kubernetes -dashboard created
服务和部署创建之后,会需要几分钟来进行启动。你可以通过运行如下命令来查看状态:
$ kubectl get deployments --namespace kube -system
$ kubectl get services --namespace kube -system
在输出像下面这样时,仪表盘就安装并准备好了:
$ kubectl get deployments --namespace kube -system
NAME DESIRED CURRENT UP -TO -DATE AVAILABLE AGE
kube -dns 1 1 1 1 1h
kubernetes -dashboard 1 1 1 1 3m
$ kubectl get services --namespace kube -system
NAME TYPE CLUSTER -IP EXTERNAL -IP PORT ( S ) AGE
kube -dns ClusterIP 10.96.0.10 < none > 53 /UDP , 53 /TCP 1h
kubernetes -dashboard ClusterIP 10.103.58.114 < none > 443 /TCP 3m
此时我们的仪表盘已处于运行中,我们要找到一种访问它的方式。这可以通过kubectl中内置的proxy服务。仅需运行如下命令来将其启动:
$ kubectl proxy
Starting to serve on 127.0.0.1 : 8001
这会启动proxy,打开浏览器访问http://127.0.0.1:8001/version/会显示集群的相关信息:
但我们想要看的是仪表盘。可通过http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/来进行访问。
首次在浏览器中打开这个URL时会出现登录界面。因为我们是通过proxy来访问仪表盘的,仅需点击SKIP按钮:
译者注: 新版的 Kubernetes 强制要求输出验证信息,没有再发现 SKIP 按钮,可通过如下命令来进行测试的 Token
$ kubectl -n kube -system describe secret $ ( kubectl -n kube -system get secret | grep admin -user | awk '{print $1}' )
登录之后,就可以看到集群上的很多信息了:
现在我们的集群已经启动并运行了,我们可以启动一些示例应用。
Kubernetes和其它Docker工具
在启动Kubernetes时,我们选择了将Kubernetes作为Docker的stack命令的默认编排器。前一章中,Docker的stack会在Docker Swarm中启动我们的Docker Compose文件。我们所使用的Docker Compose文件像下面这样:
version : "3"
services :
cluster :
image : russmckendrick /cluster
ports :
- "80:80"
deploy :
replicas : 6
restart_policy :
condition : on -failure
placement :
constraints :
- node . role == worker
我们在Kubernetes上启动应用之前,需要做一些微调并删除placement,修改后文件的内容如下:
version : "3"
services :
cluster :
image : russmckendrick /cluster
ports :
- "80:80"
deploy :
replicas : 6
restart_policy :
condition : on -failure
编辑了该文件之后,运行如下命令就会启动栈:
$ docker stack deploy --compose -file =docker -compose . yml cluster
Waiting for the stack to be stable and running . . .
cluster : Pending [ pod status : 0 /1 ready , 1 /1 pending , 0 /1 fail
cluster : Pending [ pod status : 0 /2 ready , 2 /2 pending , 0 /2 fail
cluster : Pending [ pod status : 0 /3 ready , 3 /3 pending , 0 /3 fail
cluster : Pending [ pod status : 0 /4 ready , 4 /4 pending , 0 /4 fail
cluster : Pending [ pod status : 0 /5 ready , 5 /5 pending , 0 /5 fail
cluster : Pending [ pod status : 0 /6 ready , 6 /6 pending , 0 /6 fail
cluster : Ready [ pod status : 1 /6 ready , 5 /6 pending , 0 /6 failed ]
Stack cluster is stable and running
可以看到,Docker会等待栈可用后再回到命令提示符。我们还可以运行在Docker Swarm上启动栈后查看栈相关信息相同的命令:
$ docker stack ls
$ docker stack services cluster
$ docker stack ps cluster
$ docker stack ls
NAME SERVICES ORCHESTRATOR NAMESPACE
cluster 1 Kubernetes default
$ docker stack services cluster
ID NAME MODE REPLICAS IMAGE PORTS
90fb7c7b -65a cluster_cluster replicated 4 /6 russmckendrick /cluster * : 80 -> 80 /tcp
$ docker stack ps cluster
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
90fe64f2 -65a cluster_cluster -84879989d7 -d4wrd russmckendrick /cluster docker -for -desktop Running Running 54 seconds ago * : 0 -> 80 /tcp
9100830d -65a cluster_cluster -84879989d7 -gqk52 russmckendrick /cluster docker -for -desktop Running Running 54 seconds ago * : 0 -> 80 /tcp
90ff3630 -65a cluster_cluster -84879989d7 -jpvlr russmckendrick /cluster docker -for -desktop Running Running 54 seconds ago * : 0 -> 80 /tcp
90ff33ef -65a cluster_cluster -84879989d7 -rrmht russmckendrick /cluster docker -for -desktop Running Running 54 seconds ago * : 0 -> 80 /tcp
91008a63 -65a cluster_cluster -84879989d7 -rvpnl russmckendrick /cluster docker -for -desktop Running Running 54 seconds ago * : 0 -> 80 /tcp
9100924e -65a cluster_cluster -84879989d7 -zdpwk russmckendrick /cluster docker -for -desktop Running Running 54 seconds ago * : 0 -> 80 /tcp
我们还可以使用kubectl来查看一些细节:
$ kubectl get deployments
$ kubectl get services
$ kubectl get deployments
NAME DESIRED CURRENT UP -TO -DATE AVAILABLE AGE
cluster 6 6 6 6 1m
n $ kubectl get services
NAME TYPE CLUSTER -IP EXTERNAL -IP PORT ( S ) AGE
cluster ClusterIP None < none > 55555 /TCP 1m
cluster -published LoadBalancer 10.96.156.192 localhost 80 : 31662 /TCP 1m
kubernetes ClusterIP 10.96.0.1 < none > 443 /TCP 28m
你可能注意到我们并不需要提供命名空间。这是因为我们的栈在默认命名空间中启动。同时,在列出服务时,会列出集群栈的集群 ClusterIP和LoadBalancer。查看LoadBalancer,你可以看到其外部 IP 为localhost、端口为80。
在浏览器中打开http://localhost/会显示该应用:
如果你的仪表盘还在打开的话,可以查看栈,甚至是打开其中一个容器的Terminal:
如果你的仪表盘还在打开的话,可以查看栈,甚至是打开其中一个容器的Terminal:
你可以通过运行如下命令来删除该栈:
$ docker stack rm cluster
最后再提一点,你可能会想,太好了,我可以在Kubernetes集群的任何地方运行我的 Docker Compose文件了。额,严格意义上说并不是这样的。我们说到,在第一次启动Kubernetes时,启动了一些Docker组件。它们确保Docker尽可能紧密地进行集成。但是,这些组件在非Docker管理的集群中并不存在,因此你会无法使用docker stack命令。
并非没有补救措施。Kubernetes项目中提供了一个名为Kompose工具,可接收一个Docker Compose 文件并将其实时转化为一个Kubernetes定义文件。
要在macOS上安装Kompose,运行如下命令:
$ curl -L https : //github.com/kubernetes/kompose/releases/download/v1.18.0/kompose-darwin-amd64 -o /usr/local/bin/kompose
$ chmod +x /usr /local /bin /kompose
Windows 10的用户可以使用 Chocolatey来安装这一二进制:
ℹ️Chocolatey是一个基于命令行的包管理器,可用于在Windows机器上安装各类软件包,与在Linux机器上使用yum或apt-get或者macOS上使用brew相似。
$ choco install kubernetes -kompose
最后,Linux用户可以运行如下命令:
$ curl -L https : //github.com/kubernetes/kompose/releases/download/v1.18.0/kompose-linux-amd64 -o /usr/local/bin/kompose
$ chmod +x /usr /local /bin /kompose
安装完成后,可以通过运行如下命令来启动你的Docker Compose文件:
你会得到类似下面的输出:
$ kompose up
INFO We are going to create Kubernetes Deployments , Services and PersistentVolumeClaims for your Dockerized application . If you need different kind of resources , use the 'kompose convert' and 'kubectl create -f' commands instead .
INFO Deploying application in "default" namespace
INFO Successfully created Service : cluster
INFO Successfully created Pod : cluster
Your application has been deployed to Kubernetes . You can run 'kubectl get deployment,svc,pods,pvc' for details .
根据输出中的提示,运行如下命令会给出刚刚启动的服务和pod的细节信息:
$ kubectl get deployment , svc , pods , pvc
NAME TYPE CLUSTER -IP EXTERNAL -IP PORT ( S ) AGE
service /cluster ClusterIP 10.111.18.21 < none > 80 /TCP 40s
service /kubernetes ClusterIP 10.96.0.1 < none > 443 /TCP 8h
NAME READY STATUS RESTARTS AGE
pod /cluster 1 /1 Running 0 40s
你可以通过运行如下命令来删除这些服务和pod:
$ kompose down
INFO Deleting application in "default" namespace
INFO Successfully deleted Service : cluster
INFO Successfully deleted Pod : cluster
虽然你可以使用kompose up和kompose down,我会建议生成Kubernetes定义文件并对它们按需进行修改。只需运行如下命令:
这会生成pod和服务文件:
$ kompose convert
INFO Kubernetes file "cluster-service.yaml" created
INFO Kubernetes file "cluster-pod.yaml" created
你会看到Docker Compose文件和生成的两个文件之间有相当大的不同。cluster-pod.yaml文件类似下面这样:
apiVersion : v1
kind : Pod
metadata :
creationTimestamp : null
labels :
io . kompose . service : cluster
name : cluster
spec :
containers :
- image : russmckendrick /cluster
name : cluster
ports :
- containerPort : 80
resources : { }
restartPolicy : OnFailure
status : { }
cluster-service.yaml文件类似下面这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion : v1
kind : Service
metadata :
annotations :
kompose . cmd : kompose convert
kompose . version : 1.18.0 ( 06a2e56 )
creationTimestamp : null
labels :
io . kompose . service : cluster
name : cluster
spec :
ports :
- name : "80"
port : 80
targetPort : 80
selector :
io . kompose . service : cluster
status :
loadBalancer : { }
然后你可以通过运行如下命令来启动这些文件:
$ kubectl create -f cluster -pod . yaml
$ kubectl create -f cluster -service . yaml
$ kubectl get deployment , svc , pods , pvc
$ kubectl create -f cluster -pod . yaml
pod /cluster created
$ kubectl create -f cluster -service . yaml
service /cluster created
$ kubectl get deployment , svc , pods , pvc
NAME TYPE CLUSTER -IP EXTERNAL -IP PORT ( S ) AGE
service /cluster ClusterIP 10.100.207.92 < none > 80 /TCP 5s
service /kubernetes ClusterIP 10.96.0.1 < none > 443 /TCP 8h
NAME READY STATUS RESTARTS AGE
pod /cluster 1 /1 Running 0 10s
要删除该集群的pod和服务,我们只需要运行如下命令即可:
$ kubectl delete service /cluster pod /cluster
虽然在后面的章节还会使用到Kubernetes,建议还是先在Docker桌面软件中先取消对Kubernetes的集成,因为它在空闲时会带来一些系统资源占用。只需取消勾选Enable Kubernetes即可。点击Apply时,Docker会停止所有运行Kubernetes所需的容器,但它不会删除这些镜像,这样在你重新启动它时可以很快的完成。
总结
本章中,我们通过Docker桌面软件来学习了Kubernetes。Kubernetes的内容远不止本章中所讲解的这些,所以千万不要觉得它只有这些。在讨论了Kubernetes起源之后,我们看了如何使用Docker for Mac或Docker for Windows在本地机器上启动它。
然后我们讨论了kubectl的基本使用,接着学习像Docker Swarm那样使用docker stack启动并运行应用。
本章的最后,我们讨论了Kompose,它是Kubernetes项目下的一个工具。帮助我们将Docker Compose文件转化为Kubernetes所用的文件,让我们可以将应用迁移到纯Kubernetes上。
下一章中,我们将来学习公有云上的Docker,比如Amazon Web Services,并简短地再次使用Kubernetes。
课后问题
是非题:勾选了Show system containers (advanced)之后,你就看不到用于启动Kubernetes的镜像了。
哪四个命名空间托管用于运行Kubernetes和在Docker中启动支持的容器?
你会运行哪个命令来查看pod中运行的容器的详细信息?
你会使用哪个命令来启动Kubernetes的YAML定义文件?
通常,kubectl proxy命令会在本地机器上打开哪个端口?
Google的容器编排平台的最初名称是什么?
扩展阅读
本章开始处提及的一些Google工具、PPT 和白皮书参见如下链接:
本章说涉及到的云服务的详细信息参见:
以下可以查看到Docker有关对于Kubernetes支持的声明:
最后,Kompose的主页为: