手记

精通Docker第三版 – 第九章 Docker和Kubernetes

《精通Docker第三版》完整目录:

本章中,我们一起来看Kubernetes。和Docker Swarm相似,我们可以使用Kubernetes来创建和管理用于运行基于容器的应用集群。

本章涵盖的主要内容有:

  • Kubernetes的介绍
  • 启动Kubernetes
  • 使用Kubernetes
  • Kubernetes和其它Docker工具

技术准备

Docker中的Kubernetes只支由Docker for Mac和Docker for Windows支持。和此前章节一样,作者将使用自己偏好的操作系统macOS。同样,其中极少数据的支持命令可能只在macOS中使用。

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并运行如下命令:

$ docker container ls -a

正常运行后不会显示任何容器。运行如下命令:

$ docker image ls

这会列出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 -a

因为运行上述命令会有大量输出,以下仅显示容器的名称。通过运行如下命令来进行实现:

$ docker container ls --format {{.Names}}

运行该命令会得到如下输出:

$ 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中默认配置的命名空间:

$ kubectl get namespaces

然后通过如下命令来在命名空间中查看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命名空间。

该命令的完整输出如下所示:

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:

你可以通过运行如下命令来删除该栈:

$ 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

你会得到类似下面的输出:

$ 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定义文件并对它们按需进行修改。只需运行如下命令:

$ kompose convert

这会生成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文件类似下面这样:

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的主页为:

2人推荐
随时随地看视频
慕课网APP

热门评论

Deploy Docker Stacks to Kubernetes by default

这个是做什么用的?

查看全部评论