回到首页

输入关键词,多个关键词用空格分隔。

← 工程原理与设计 · 系列目录

Kubernetes 学习笔记

约 8 分钟
本页目录

主要来源于官网的教程,从基础入手,循序渐进,还有在线实验,非常友好


更新历史

  • 2017.06.05: 开始学习

Kubernetes 基础

先来看一段来自这里的简介(我更新了一下链接):

Kubernetes 是 Google 开源的容器集群管理系统,其提供应用部署、维护、扩展机制等功能,利用Kubernetes 能方便地管理跨机器运行容器化的应用。Kubernetes 可以在物理机或虚拟机上运行,且支持部署到 AWS,Azure,GCE 等多种公有云环境。介绍分布式训练之前,需要对 Kubernetes 有一个基本的认识,下面先简要介绍一下本文用到的几个 Kubernetes 概念。

  • Node 表示一个 Kubernetes 集群中的一个工作节点,这个节点可以是物理机或者虚拟机,Kubernetes 集群就是由 node 节点与 master 节点组成的。
  • Pod 是一组(一个或多个)容器,pod 是 Kubernetes 的最小调度单元,一个 pod 中的所有容器会被调度到同一个 node 上。Pod 中的容器共享 NET,PID,IPC,UTS 等 Linux namespace。由于容器之间共享 NET namespace,所以它们使用同一个 IP 地址,可以通过 localhost 互相通信。不同 pod 之间可以通过IP地址访问。
  • Job 描述 Kubernetes 上运行的作业,一次作业称为一个 job,通常每个 job 包括一个或者多个pods,job 启动后会创建这些 pod 并开始执行一个程序,等待这个程序执行成功并返回 0 则成功退出,如果执行失败,也可以配置不同的重试机制。
  • Volume 存储卷,是 pod 内的容器都可以访问的共享目录,也是容器与 node 之间共享文件的方式,因为容器内的文件都是暂时存在的,当容器因为各种原因被销毁时,其内部的文件也会随之消失。通过 volume,就可以将这些文件持久化存储。Kubernetes 支持多种 volume,例如 hostPath(宿主机目录),gcePersistentDisk,awsElasticBlockStore等。
  • Namespaces 命名空间,在 kubernetes 中创建的所有资源对象(例如上文的 pod,job)等都属于一个命名空间,在同一个命名空间中,资源对象的名字是唯一的,不同空间的资源名可以重复,命名空间主要为了对象进行逻辑上的分组便于管理。本文只使用了默认命名空间。
  • PersistentVolume: 和 PersistentVolumeClaim 结合,将外部的存储服务在 Kubernetes 中描述成为统一的资源形式,便于存储资源管理和 Pod 引用。

如果看不懂,也没有关系,接下来会更详细介绍。PS. 官方文档很有灵性,建议有英文阅读能力的同学去通读一遍,这里只是我的一些学习笔记,不如原版这么有逻辑性。

Kubernetes 集群让多台机器像一个单一组件一样运行,但是有一个前提条件,就是应用需要被打包到容器里。打包好之后 Kubernetes 会自动化地以一种高效的形式去调度容器们。一个 Kubernetes 集群有两种类型的资源:

  • Master 负责调度集群,维护应用状态,扩展应用和滚动更新

  • Nodes 负责运行各个应用。每个节点有一个 Kubelet,是在每个节点上的客户端,负责与 master 交流。一个 Kubernetes 集群至少需要 3 个 node。

    • 如果想要体验一下,可以使用 Minikube,会在单机上创建虚拟机来搭建集群(本文的教程也是用这个来展示的)

创建集群

命令如下

# 查看版本
$> minikube version
minikube version: v0.15.0-katacoda

# 启动集群
$> minikube start
Starting local Kubernetes cluster...

# 查看版本
$> kubectl version
Client Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.2", GitCommit:"08e09955
4f3c31f6e6f07b448ab3ed78d0520507", GitTreeState:"clean", BuildDate:"2017-01-12T04:57:25Z",
GoVersion:"go1.7.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.2", GitCommit:"08e09955
4f3c31f6e6f07b448ab3ed78d0520507", GitTreeState:"clean", BuildDate:"1970-01-01T00:00:00Z",
GoVersion:"go1.7.1", Compiler:"gc", Platform:"linux/amd64"}

# 查看集群状态
$> kubectl cluster-info
Kubernetes master is running at http://host01:8080
heapster is running at http://host01:8080/api/v1/proxy/namespaces/kube-system/services/heap
ster
kubernetes-dashboard is running at http://host01:8080/api/v1/proxy/namespaces/kube-system/s
ervices/kubernetes-dashboard
monitoring-grafana is running at http://host01:8080/api/v1/proxy/namespaces/kube-system/ser
vices/monitoring-grafana
monitoring-influxdb is running at http://host01:8080/api/v1/proxy/namespaces/kube-system/se
rvices/monitoring-influxdb

# 获取可用的 node
$> kubectl get nodes
NAME      STATUS    AGE
host01    Ready     15m

部署应用

Kubernetes 集群启动之后,就可以在这之上部署应用了。部署应用的时候 master 会进行调度并选择合适的 node,启动之后仍旧会继续监控,一旦出问题,就会自动重新启用。

我们可以使用 Kubernetes 命令行工具 Kubectl 通过 Kubernetes API 来管理部署。创建部署的时候需要指定镜像和要运行的副本个数(当然也可以后面更新),然后们就实际来部署一波,命令如下:

# 部署应用
$> kubectl run kubernetes-bootcamp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --port=8080
mp:v1 --port=8080ubernetes-bootcamp --image=docker.io/jocatalin/kubernetes-bootca
deployment "kubernetes-bootcamp" created

# 列出部署
$> kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   1         1         1            1           1m

# 查看部署
# 先通过 proxy 连接到正在运行的容器
$> kubectl proxy
Starting to serve on 127.0.0.1:8001

# 然后打开一个新 tab,输出 Pod 名字
$> export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
$> echo Name of the Pod: $POD_NAME
Name of the Pod: kubernetes-bootcamp-390780338-n7q3n

# 获取这个 pod 的输出
$> curl http://localhost:8001/api/v1/proxy/namespaces/default/pods/$POD_NAME/
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-390780338-n7q3n | v=1

查看应用

每个应用会在一个 Pod 中运行,一个 Pod 里可以有一个或多个应用(相当于给这些应用创建了一个共有的 localhost 环境,每个 pod 里的网络等环境是共享的)。

每个 Pod 都会运行在一个 Node 上,每个 Node 都由 Master 来管理。其中,每个 Node 都必须要有:

  • Kubelet,负责与 Master 通讯,管理 node 上运行的 pods 和 containers
  • 一个容器的 runtime,比如 docker,用来从 registry 拉取镜像,解压与运行应用

常用的 kubectl 命令有

  • kubectl get 列出所有的资源
  • kubectl describe 显示资源的详细信息
  • kubectl logs 输出一个 pod 中一个 container 的日志
  • kubectl exec 在一个 pod 中的一个 container 中执行命令

例子如下:

# 获取 pod 信息
$> kubectl get pods
NAME                                  READY     STATUS    RESTARTS   AGE
kubernetes-bootcamp-390780338-6b9n3   1/1       Running   0          41m

# 查看 pods 详细信息
# 包括 镜像、IP 等各类信息,describe 不仅可以用于 pods,node 和 deployment 都可以
$> kubectl describe pods
Name:           kubernetes-bootcamp-390780338-6b9n3
Namespace:      default
Node:           host01/172.17.0.41
Start Time:     Mon, 05 Jun 2017 03:05:07 +0000
Labels:         pod-template-hash=390780338
                run=kubernetes-bootcamp
Status:         Running
IP:             172.18.0.2
Controllers:    ReplicaSet/kubernetes-bootcamp-390780338
Containers:
  kubernetes-bootcamp:
    Container ID:       docker://9308ecb7bb592255b5fb517ec7caa13703f7b5bb41a24145ba1eeb670693a60d
    Image:              docker.io/jocatalin/kubernetes-bootcamp:v1
    Image ID:           docker-pullable://jocatalin/kubernetes-bootcamp@sha256:0d6b8ee63bb5
7c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af
    Port:               8080/TCP
    State:              Running
      Started:          Mon, 05 Jun 2017 03:05:08 +0000
    Ready:              True
    Restart Count:      0
    Volume Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-74qlr (ro)
    Environment Variables:      <none>
Conditions:
  Type          Status
  Initialized   True
  Ready         True
  PodScheduled  True
Volumes:
  default-token-74qlr:
    Type:       Secret (a volume populated by a Secret)
    SecretName: default-token-74qlr
QoS Class:      BestEffort
Tolerations:    <none>
Events:
  FirstSeen     LastSeen        Count   From                    SubObjectPath             Type             Reason          Message
  ---------     --------        -----   ----                    -------------             -------- ------          -------
  41m           41m             1       {default-scheduler }                              Normal           Scheduled       Successfully assigned kubernetes-bootcamp-390780338-6b9n3 to host01
  41m           41m             1       {kubelet host01}        spec.containers{kubernetes-bootcamp}       Normal          Pulled          Container image "docker.io/jocatalin/kubernetes-bootcamp:v1" already present on machine
  41m           41m             1       {kubelet host01}        spec.containers{kubernetes-bootcamp}       Normal          Created         Created container with docker id 9308ecb7bb59; Security:[seccomp=unconfined]
  41m           41m             1       {kubelet host01}        spec.containers{kubernetes-bootcamp}       Normal          Started         Started container with docker id 9308ecb7bb
59

# 获取 pod 信息
$> export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
$> echo Name of the Pod: $POD_NAME
Name of the Pod: kubernetes-bootcamp-390780338-6b9n3

# 查看 pod 日志
$> kubectl logs $POD_NAME
Kubernetes Bootcamp App Started At: 2017-06-05T03:05:08.494Z | Running On:  kubernetes-bootcamp-390780338-6b9n3

使用服务暴露应用

Pods 是有生命周期的,也有独立的 IP 地址,随着 Pods 的创建与销毁,一个必不可少的工作就是保证各个应用能够感知这种变化。这就要提到 Service 了,Service 是 YAML 或 JSON 定义的由 Pods 通过某种策略的逻辑组合。更重要的是,Pods 的独立 IP 需要通过 Service 暴露到网络中,有以下几种方式:

  • ClusterIP(默认):只在集群内部可见的地址
  • NodePort:可在集群外访问,需要指定端口
  • LoadBalancer:创建一个负载均衡器,IP 是固定的
  • ExternalName:使用任意的名字暴露服务

依然是通过实例来感受一下

# 查看 pods 信息
$> kubectl get pods
NAME                                  READY     STATUS    RESTARTS   AGE
kubernetes-bootcamp-390780338-76skz   1/1       Running   0          6s

# 查看服务信息
$> kubectl get services
NAME         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   10.0.0.1     <none>        443/TCP   47s

# 暴露服务
$> kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
service "kubernetes-bootcamp" exposed

扩展应用

当业务流量暴涨,就需要根据需要扩展应用(多几个 pods),具体的原理比较简单,我们直接来看例子:

TODO

更新应用

滚动更新可以保证 0 停机时间,其实逻辑和前面的扩展差不多,可以认为是用新版本的扩展,也直接来看例子:

TODO

Hello Minikube

一个简单的教程,学习如何把本机的代码转换成 Kubernetes 可以使用的镜像

部署

hosted solution

turnkey cloud solutions

CentOS Version

参考链接

相关文章