teleSOHO.com

kubernets入门

kubernets入门

Kubernetes 是用于自动部署,扩展和管理容器化应用程序的开源系统。Kubernetes是构建在Google 15年生产环境经验基础之上,并结合来自社区的最佳创意和实践。

使用和理解Kubernetes

使用Kubernetes,可以通过Kubernetes API对象(主要是命令kubectl)来定义集群的预期状态(desired state)*。一旦你设置目标状态,Kubernetes会自动执行各类任务。

Kubernetes对象

  1. 使用yaml来定义Kubernetes对象,

     apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
     kind: Deployment
     metadata:
     name: nginx-deployment
     spec:
     selector:
         matchLabels:
         app: nginx
     replicas: 2 # tells deployment to run 2 pods matching the template
     template:
         metadata:
         labels:
             app: nginx
         spec:
         containers:
         - name: nginx
             image: nginx:1.7.9
             ports:
             - containerPort: 80
    
  2. 使用kubectl创建kubernetes对象

     kubectl create -f https://k8s.io/examples/application/deployment.yaml --record
    

创建集群(Create a Cluser)

确认kubernetes版本

$ minikube version
minikube version: v0.34.1

输入minikube start启动集群:

$ minikube start
o   minikube v0.34.1 on linux (amd64)
>   Configuring local host environment ...
>   Creating none VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...
-   "minikube" IP address is 172.17.0.82
-   Configuring Docker as the container runtime ...
-   Preparing Kubernetes environment ...
@   Downloading kubelet v1.13.3
@   Downloading kubeadm v1.13.3
-   Pulling images required by Kubernetes v1.13.3 ...
-   Launching Kubernetes v1.13.3 using kubeadm ...
-   Configuring cluster permissions ...
-   Verifying component health .....
+   kubectl is now configured to use "minikube"
=   Done! Thank you for using minikube!

确认集群信息

$ kubectl cluster-info
Kubernetes master is running at https://172.17.0.82:8443
KubeDNS is running at https://172.17.0.82:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

确认节点信息

$ kubectl get nodes
NAME       STATUS   ROLES    AGE    VERSION
minikube   Ready    master   8m8s   v1.13.3

创建应用部署

通过kubectl run命令部署一个docker镜像(https://gcr.io/google-samples/kubernetes-bootcamp:v1)

$ kubectl run kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1 --port=8080
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/kubernetes-bootcamp created
$

应用部署会完成如下工作:

  • 查找可运行应用的节点;
  • 在应用加入节点运行计划;
  • 配置集群在需要的时候在新的节点上启动应用。

集群根据计划在节点上启动应用(称为:Pod),可以通过命令来查看部署信息:

$ kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   1/1     1            1           12m

查看Pods和Nodes

在创建Deployment时,Kubernetes会创建一个Pod来托管应用。Pod是Kubernetes中一个抽象化概念,由一个或多个容器组合在一起得共享资源。这些资源包括:

  • 共享存储,如 Volumes 卷
  • 网络,唯一的集群IP地址
  • 每个容器运行的信息,例如:容器镜像版本

Pod模型是特定应用程序的“逻辑主机”,并且包含紧密耦合的不同应用容器。

Pod中的容器共享IP地址和端口。

Pod是Kubernetes中的最小单位,当在Kubernetes上创建Deployment时,该Deployment将会创建具有容器的Pods(而不会直接创建容器),每个Pod将被绑定调度到Node节点上,并一直保持在那里直到被终止(根据配置策略)或删除。在节点出现故障的情况下,群集中的其他可用节点上将会调度之前相同的Pod。

Pods是私有的,默认只能在集群里访问。但我们可以新开一个终端,然后使用kubectl命令生成一个代理接口(proxy)1

$ kubectl proxy
Starting to serve on 127.0.0.1:8001

接口公开后,就可以通过http协议查询API版本信息:

$ curl http://localhost:8001/version
{
  "major": "1",
  "minor": "13",
  "gitVersion": "v1.13.3",
  "gitCommit": "721bfa751924da8d1680787490c54b9179b1fed0",
  "gitTreeState": "clean",
  "buildDate": "2019-02-01T20:00:57Z",
  "goVersion": "go1.11.5",
  "compiler": "gc",
  "platform": "linux/amd64"
}

API服务器会自动为每个Pod生成一个基于pod名称的endpoint2,同样也可以通过上面的Proxy1来访问。

首先我们得获取Pod名称并保存到环境变量POD_NAME中:

$ export POD_NAME=$(kubectl get pods -o go-template --template '\n')
$ echo Name of the Pod: $POD_NAME
Name of the Pod: kubernetes-bootcamp-6bf84cb898-859bp

然后我们可以通过HTTP请求去运行Pod上的应用:

$ curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME/proxy/
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-6bf84cb898-859bp | v=1

获取Pod日志

$ kubectl logs $POD_NAME
Kubernetes Bootcamp App Started At: 2019-03-14T02:36:39.795Z | Running On:  kubernetes-bootcamp-6bf84cb898-s2pr5

Running On: kubernetes-bootcamp-6bf84cb898-s2pr5 | Total Requests: 1 | App Uptime: 199.088 seconds | Log Time: 2019-03-14T02:39:58.884Z
Running On: kubernetes-bootcamp-6bf84cb898-s2pr5 | Total Requests: 2 | App Uptime: 799.364 seconds | Log Time: 2019-03-14T02:49:59.159Z

一旦Pod已经启动和执行,就可以使用exec命令去执行容器内部的命令:

比如显示容器的环境变量:

$ kubectl exec $POD_NAME env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=kubernetes-bootcamp-6bf84cb898-s2pr5
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
NPM_CONFIG_LOGLEVEL=info
NODE_VERSION=6.3.1
HOME=/root

接下来,启动容器的一个bash会话(session):

$ kubectl exec -ti $POD_NAME bash
root@kubernetes-bootcamp-6bf84cb898-s2pr5:/#

查看容器的原始代码:

root@kubernetes-bootcamp-6bf84cb898-s2pr5:/# cat server.js
var http = require('http');
var requests=0;
var podname= process.env.HOSTNAME;
var startTime;
var host;
var handleRequest = function(request, response) {
  response.setHeader('Content-Type', 'text/plain');
  response.writeHead(200);
  response.write("Hello Kubernetes bootcamp! | Running on: ");
  response.write(host);
  response.end(" | v=1\n");
  console.log("Running On:" ,host, "| Total Requests:", ++requests,"| App Uptime:", (new Date() - startTime)/1000 , "seconds", "| Log Time:",new Date());
}
var www = http.createServer(handleRequest);
www.listen(8080,function () {
    startTime = new Date();;
    host = process.env.HOSTNAME;
    console.log ("Kubernetes Bootcamp App Started At:",startTime, "| Running On: " ,host, "\n" );
});

确定应用运行状态:

root@kubernetes-bootcamp-6bf84cb898-s2pr5:/# curl localhost:8080
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-6bf84cb898-s2pr5 | v=1

退出容器bash:

root@kubernetes-bootcamp-6bf84cb898-s2pr5:/# exit
exit

通过服务暴露应用

Kubernetes Services概述

(凡人皆有一死来描述pod,没有比这跟准确的了)。事实上,Pod是有生命周期的。当一个工作节点(Node)销毁时,节点上运行的Pod也会销毁,然后通过ReplicationController动态创建新的Pods来保持应用的运行。作为另一个例子,考虑一个图片处理 backend,它运行了3个副本,这些副本是可互换的 —— 前端不需要关心它们调用了哪个 backend 副本。也就是说,Kubernetes集群中的每个Pod都有一个独立的IP地址,甚至是同一个节点上的Pod,因此需要有一种方式来自动协调各个Pod之间的变化,以便应用能够持续运行。

Kubernetes中的Service 是一个抽象的概念,它定义了Pod的逻辑分组和一种可以访问它们的策略,这组Pod能被Service访问,使用YAML (优先)或JSON 来定义Service,Service所针对的一组Pod通常由LabelSelector实现(参见下文,为什么可能需要没有 selector 的 Service)。

可以通过type在ServiceSpec中指定一个需要的类型的 Service,Service的四种type:

  • ClusterIP(默认) - 在集群中内部IP上暴露服务。此类型使Service只能从群集中访问。
  • NodePort - 通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。
  • LoadBalancer - 使用云提供商的负载均衡器(如果支持),可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
  • ExternalName - 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容,没有任何类型代理被创建。这种类型需要v1.7版本或更高版本kube-dnsc才支持。

更多不同类型Service的信息,请参考“Using Source IP”教程,Connecting Applications with Services。

使用ExternalName类型可以实现一种情况,在创建Service涉及未定义selector的示例,创建的Service selector不创建相应的Endpoints对象,可以通过手动将Service映射到特定Endpoints。

Kubernetes Service 是一个抽象层,它定义了一组逻辑的Pods,借助Service,应用可以方便的实现服务发现与负载均衡。

  1. 创建新服务

    先获取节点信息:

     $ kubectl get nodes
     NAME       STATUS   ROLES    AGE    VERSION
     minikube   Ready    master   118s   v1.13.3
    

    再获取服务信息:

     $ kubectl get services
     NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
     kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   2m
    

    可以看到,我们已经有了一个minikube启动的时候默认创建的服务kubernetes,可以通过expose命令去创建一个新的服务:

     $ kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
     service/kubernetes-bootcamp exposed
     $ kubectl get services
     NAME                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
     kubernetes            ClusterIP   10.96.0.1        <none>        443/TCP          4m15s
     kubernetes-bootcamp   NodePort    10.101.151.177   <none>        8080:32377/TCP   94s
    

    现在我们有了一个运行中的服务kubernetes-bootcamp,该服务有一个唯一的簇IP、一个内部端口号和一个外部IP。

    可以使用kubectl describe查看kubernetes-bootcamp服务的详细信息:

     $ kubectl describe services/kubernetes-bootcamp
     Name:                     kubernetes-bootcamp
     Namespace:                default
     Labels:                   run=kubernetes-bootcamp
     Annotations:              <none>
     Selector:                 run=kubernetes-bootcamp
     Type:                     NodePort
     IP:                       10.101.151.177
     Port:                     <unset>  8080/TCP
     TargetPort:               8080/TCP
     NodePort:                 <unset>  32377/TCP
     Endpoints:                172.18.0.4:8080
     Session Affinity:         None
     External Traffic Policy:  Cluster
     Events:                   <none>
    
  2. 使用标签

    标签可以在创建时附加到对象上,或者过后附加到对象上。可以使用kubectl describe查看pod的标签。

     $ kubectl describe pods $POD_NAME
     Name:               kubernetes-bootcamp-6bf84cb898-trwjj
     Namespace:          default
     Priority:           0
     PriorityClassName:  <none>
     Node:               minikube/172.17.0.15
     Start Time:         Thu, 14 Mar 2019 07:15:58 +0000
     Labels:             app=v1
                         pod-template-hash=6bf84cb898
                         run=kubernetes-bootcamp
     Annotations:        <none>
     Status:             Running
     IP:                 172.18.0.4
     Controlled By:      ReplicaSet/kubernetes-bootcamp-6bf84cb898
     Containers:
     kubernetes-bootcamp:
         Container ID:   docker://f6aaa7c355a4073d88622fa66e4c8a7854b860997127d9629e30f114351bb817
         Image:          gcr.io/google-samples/kubernetes-bootcamp:v1
         Image ID:       docker-pullable://jocatalin/kubernetes-bootcamp@sha256:0d6b8ee63bb57c5f5b6156f446b3bc3b3c143d233037f3a2f00e279c8fcc64af
         Port:           8080/TCP
         Host Port:      0/TCP
         State:          Running
         Started:      Thu, 14 Mar 2019 07:16:01 +0000
         Ready:          True
         Restart Count:  0
         Environment:    <none>
         Mounts:
         /var/run/secrets/kubernetes.io/serviceaccount from default-token-vwx9d (ro)
     Conditions:
     Type              Status
     Initialized       True
     Ready             True
     ContainersReady   True
     PodScheduled      True
     Volumes:
     default-token-vwx9d:
         Type:        Secret (a volume populated by a Secret)
         SecretName:  default-token-vwx9d
         Optional:    false
     QoS Class:       BestEffort
     Node-Selectors:  <none>
     Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                     node.kubernetes.io/unreachable:NoExecute for 300s
     Events:
     Type    Reason     Age    From               Message
     ----    ------     ----   ----               -------
     Normal  Scheduled  5m31s  default-scheduler  Successfully assigned default/kubernetes-bootcamp-6bf84cb898-trwjj to minikube
     Normal  Pulled     5m29s  kubelet, minikube  Container image "gcr.io/google-samples/kubernetes-bootcamp:v1" already present on machine
     Normal  Created    5m28s  kubelet, minikube  Created container
     Normal  Started    5m28s  kubelet, minikube  Started container
    

    这里看到这个Pod有3个标签,可以通过标签来查询Pod列表。

     $ kubectl get pods -l app=v1
     NAME                                   READY   STATUS    RESTARTS   AGE
     kubernetes-bootcamp-6bf84cb898-trwjj   1/1     Running   0          11m
     $ kubectl get pods -l run=kubernetes-bootcamp
     NAME                                   READY   STATUS    RESTARTS   AGE
     kubernetes-bootcamp-6bf84cb898-trwjj   1/1     Running   0          11m
    

    或者通过标签删除服务。

     $ kubectl delete service -l run=kubernetes-bootcamp
     service "kubernetes-bootcamp" deleted
     $ kubectl get services
     NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
     kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   24m    
    

    服务被删除后,将无法从簇外部访问应用:

     $ curl $(minikube ip):$NODE_PORT
     curl: (7) Failed to connect to 172.17.0.15 port 80: Connection refused
    

    但,如果执行Pod内部的curl,可以看到应用是运行状态的。

     $ kubectl exec -ti $POD_NAME curl localhost:8080
     Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-6bf84cb898-trwjj | v=1    
    

应用伸缩(Scale Your App)

前面,我们创建了一个Deployment,然后通过Service暴露,Deployment创建的Pod来运行应用,当流量增加时,我们需要扩展应用来满足用户需求。

通过Deployment更改副本数可以实现伸缩。

使用Deployment扩展能确保在新的可用Node资源上创建Pods,缩小比例将减少Pod的数量到理想状态。如果伸缩需求是0,将会终止Deployment指定的所有Pod。Kubernetes还支持自动缩放Pods

运行应用将要考虑一些情况,需要将流量分配给所有实例。Service集成了负载均衡器,可以将网络流量分配到Deployment暴露的所有Pod中。Service将使用Endpoints持续监控运行的Pod,以确保仅将流量分配到可用的Pod。

首先,看看当前的deployments:

$ kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   1/1     1            1           3m7s

接着,使用scale命令调整部署为4个副本:

$ kubectl scale deployments/kubernetes-bootcamp --replicas=4
deployment.extensions/kubernetes-bootcamp scaled

再次查看deployments,可以看到已有4个可用的应用。

$ kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   4/4     4            4           3m15s

接下来,可以查看运行pod的数量:

$ kubectl get pods -o wide
NAME                                   READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
kubernetes-bootcamp-6bf84cb898-54mht   1/1     Running   0          6m58s   172.18.0.6   minikube   <none>           <none>
kubernetes-bootcamp-6bf84cb898-78zvd   1/1     Running   1          10m     172.18.0.4   minikube   <none>           <none>
kubernetes-bootcamp-6bf84cb898-pz67p   1/1     Running   0          6m58s   172.18.0.7   minikube   <none>           <none>
kubernetes-bootcamp-6bf84cb898-tzhld   1/1     Running   0          6m58s   172.18.0.5   minikube   <none>           <none>

相关文档

  1. By definition, Web services can be communicated with over a network using industry standard protocols, including SOAP. That is, a client and a Web service communicate using SOAP messages, which encapsulate the in and out parameters as XML. Fortunately, for Web service clients, the proxy class handles the work of mapping parameters to XML elements and then sending the SOAP message over the network.  2

  2. the endpoint is the URL where your service can be accessed by a client application. 

← 开发小程序有什么好处?