「Kubernetes」- 部署 Web 应用(快速开始)

问题描述

1)管理 Kubernetes 基础的工作负载(Workloads):「部署」和「POD」;
2)通过命令行和 YAML 文件,创建「部署」和「POD」;
3)以及如何「伸缩」和「更新」部署;

该笔记将记录:在 Kubernetes Cluster 中,部署演示使用的 Web 应用,以快速入门;

解决方案

清单文件格式

kubectl 可以非常简单的部署一个对象,但是更多的细节需要通过清单文件控制;

kind: Pod
apiVersion: v1
metadata:
  name: mypod
# 还可以包含 spec 字段
# spec:
#   ...

快速创建用于测试的网站(Nginx)

Run a Stateless Application Using a Deployment | Kubernetes

kubectl apply -f - <<EOF
---
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: nginx:1.14.2
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  # type: NodePort
  type: LoadBalancer
  ports:
  - port: 8080
    targetPort: 80
  selector:
    app: nginx
EOF

Simple Website

MySQL

cat > mysql.yaml <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "123456"
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: mysql
EOF

kubectl apply -f mysql.yaml

Tomcat

cat > myweb.yaml <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myweb
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myweb
  template:
    metadata:
      labels:
        app: myweb
    spec:
      containers:
      - name: myweb
        image: kubeguide/tomcat-app:v1
        ports:
        - containerPort: 8080
        env:
        - name: MYSQL_SERVICE_HOST
          value: 'mysql'
        - name: MYSQL_SERVICE_PORT
          value: '3306'
---
apiVersion: v1
kind: Service
metadata:
  name: myweb
spec:
  ports:
  - port: 8080
  selector:
    app: myweb
EOF

kubectl apply -f myweb.yaml

Ingress

cat > myweb-ingress.yaml <<EOF
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: myweb-ingress
  annotations:
    # use the shared ingress-nginx
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: "k8s-ingress.example.xyz"
    http:
      paths:
      - path: /
        backend:
          serviceName: myweb
          servicePort: 8080
EOF

kubectl apply -f ./myweb-ingress.yaml

访问页面

返回如下页面表示成功:

常见 Port 位置及含义

每个节点上都运行 kube-proxy 容器,它的作用是操作 iptables 规则,kube-proxy 会在防火墙上配置 DNAT 规则,将指定端口的访问传递给对应的容器;

在 Kubernetes 1.9.1 中,开始 beta 版本 IPVS 特性,也是在操作 Netfilter 进行流量转发;

在 Service 中

targetPort
在「Pod」中的容器的端口;

port
由「Service」暴露的端口。在容器内部使用,供容器之间访问;

nodePort
外部机器可访问的端口。在「Node」上暴露的端口,可以通过「IPAddress:Port」的形式直接访问;

在 Ingress 中

ServicePort
在 Ingress 中,能够看到对应关系,ServicePort 对于 Serivce 的 Port 参数;

常用命令汇总

更新 Deployment 的某个镜像:

# kubectl set image deployment/my-deployment mycontainer=myimage:latest

4.1. Creating a Deployment Using kubectl run

使用 kubectl run 命令创建部署:

# kubectl run ghost –images=ghost:0.9

# kubectl get deployment/ghost

可以通过选项指定部署参数:–env, –port, –command, –expose, –replicas

kubectl run ghost –image=ghost:0.9 –port=2368 –expose # 在 2368 端口启动 Ghost,并创建一个服务;

kubectl run mysql –image=mysql:5.5 –env=MYSQL_ROOT_PASSWORD=root # 使用 ROOT 密码启动 MySQL 服务;

kubectl run myshell –image=busybox –command — sh -c “sleep 135142” # 启动 Busybox 容器,并运行指定的命令;

4.2. Creating Objects from File Manifests

还可以通过清单文件创建:

# kubectl create -f <manifest>

下面是一个「命名空间」的清单文件的示例:

# myns.yaml
apiVersion: v1
kind: namespace
metadata:
	name: myns

使用kubectl create -f myns.yaml命令创建该对象;

还可以使用 URL 来创建:kubectl create -f https://example.com/path/to/foo.yaml

4.3. Writing a Pod Manifest from Scratch

从零编写一个「Pod」文件,Pod 是一个 /api/v1 的对象,和其他 Kubernetes 对象类似,清单文件包含以下字段:

apiVerison:指定 API 版本

kind:指定对象类型

metadata:提供对象相关的元数据

spec:指定对象的规则

Pod 的清单文件包含一组容器以及一组可选的卷,下面是一个简单的例子,只包含一个容器,不包含卷:

# mpod.yaml
apiVersion: v1
kind: pod
metadata:
  name: mPod
spec:
  containers:
  - name: mPod
    image: nginx

使用kubectl create -f mpod.yaml创建该 POD;

与上述示例相比,真正的 Pod 的 API 规格要复杂得多。例如 POD 可以包含多个容器:

# mpod.yaml
apiVersion: v1
kind: pod
metadata:
  name: mPod
spec:
  containers:
  - name: mPod
    image: nginx
  - name: mPod
    image: nginx

「Pod」中还可以包含「卷」的定义,用于在容器中加载数据,还可以探测容器的应用程序的健康状况;

更多关于规则字段的描述,以及 API 对象的所有规则,可以参考「Pods」手册;

不要单独创建「Pod」,应该创建「部署」对象来监管「Pod」,它会通过另外一个 ReplicaSet 的对象监控「Pod」;

4.4. Launching a Deployment Using a Manifest

使用 Deployment 控制应用的启动和监控;

# fan.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: fancyapp
spec:
  replicas: 5
  template:
    metadata:
      labels:
        app: fancy
        env: development
      spec:
        containers:
        - name: sise
          image: demo:0.5.-
          ports:
          - containerPort: 9876
          env:
          - name: SIMPLE_SERVICE_VERSION
            value: "0.9"

可以看出,启动该应用的时候,有几件事情需要明确指定:

  • 设置 Pod 的数量;
  • 贴上标签,比如 env=development;
  • 设置环境变量,比如 SIMPLE_SERVICE_VERSION;

kubectl create -f fan.yaml

kubectl get deploy

kubectl get replicaset

kubectl get pods

!!!如果要删除副本集和监管的 Pod,那么需要删除部署,即 kubectl delete deployment/fancyapp。不要单独删除 Pod,因为删除 Pod 会重建;

部署允许用户伸缩应用的规模,也可以升级和回滚到前一个版本。一般来说,对于需要多个具有相同特征的 pod 的无状态应用来说,这些方法非常实用;

!!!通常「部署」负责监管「Pod」和「副本集」,允许你细致地控制如何以及何时应该将该 Pod 升级到最新的版本,或者回滚到之前的版本。在某些特殊情况下爱,比如需要调试某个 Pod,可以在部署的不同版本之间切换!!!

!!!「副本集」将取代「副本控制器」,二者的区别是「副本集」支持以集合为基础的标签与查询,但是以后「副本集」可能会有更多的新功能加入,将淘汰「副本控制器」!!!

可以使用 kubectl create 命令及–dry-run 选项生成清单文件。可以先生成 YAML 或 JOSN 格式的清单文件,方便以后使用:

# kubectl create deployment fancyapp –image nginx -o json –dry-run

关于「部署」可以参考「Deployments」手册;

4.5. Updating a Deployment

如何将「部署」更新到新版本的程序?

只需要更新部署:

# kubectl run sise –image=afdae/simvsaf:0.4.0

# kubectl set image deployment sise –image=afdae/simvsaf:0.4.0

# kubectl rollout status deployment sise

# kubectl rollout history deployment sise

如果想修改部署,可以使用kubectl edit deployment sise,该命令会在编辑器中打开部署文件,退出编辑器后自动更新部署。使用 KUBE_EDITOR 环境变量指定的编辑器;

使用kubectl rollout history deployment sise查看;

可以使用kubectl create--record选项指定 CHANGE-CAUSE 列。如果向了解什么变更触发了新版本,则可以加上此选项;

还有一些其他可以更新部署的命令:

# kubectl apply -f foo.yaml # 更新清单文件更新部署;

# kubectl replace -f bar.yaml # 替换部署,但替换的部署对象必须存在;

# kubectl patch demployment sise -p ‘{“spec”:{“template”:{“spec”:{“containers”:[{“name”:”sise”, “image”:”simpadfas:0.5.0″}]}}}}’

另外可以撤回操作:kubetl rollout undo deployment sise ??to?revision=2

然后使用kubectl get deployment/sise -o yaml确认回退成功;

只有 POD 模板(在.spec.template 下的键值)的变更才会触发新的部署,例如环境变量、端口号、容易映像等等。部署方面的变更,比如副本个数,不会触发新的部署;

参考文献

一个简单的 Kubernetes 应用部署示例
Kubernetes 中的 nodePort,targetPort,port 的区别和意义(转)
Kubernetes how to make Deployment to update image
Basic usage – NGINX Ingress Controller