kubernetes快速入门(上)


1 简介

1.1 虚拟机和容器的区别

图1

1.2 容器技术和docker的关系

1.3 容器的单一职责原则

1.4 什么是Kubernetes

图2

图3

1.5 K8s和Docker的关系

1.6 创建一个Docker镜像

在开发环境安装Docker环境之后,我们可以创建一个Node.js的应用(参考),该应用接收HTTP请求,并且进行响应。

const http = require('http');
const os = require('os');

// 输出服务器启动日志
console.log("Kubia server starting...");

// 定义请求处理函数,接收request和response
var handler = function(request, response) {
  console.log("Received request from " + request.connection.remoteAddress);
  
  // 设置HTTP响应状态码为200
  response.writeHead(200);
  // 响应hostname
  response.end("This is v1 running in pod " + os.hostname() + "\n");
};

// 创建HTTP服务器实例
var www = http.createServer(handler);
// 启动服务器监听8080端口
www.listen(8080);
FROM node:7                   # 构建所基于的基础镜像
ADD app.js /app.js            # 把app.js文件从本地文件夹添加到镜像的根目录
ENTRYPOINT ["node", "app.js"] # 当镜像被运行时需要被执行的命令
- image:
  - app.js
  - Dockerfile

图4

到这里我们已经介绍了容器/k8s相关的基本知识,接下来介绍k8s中的相关概念。

2 Pod

2.1 什么是Pod

Pod是在 K8s中创建和管理的、最小的可部署的计算单元, 它在Worker Node之间进行调度。

2.2 为什么需要Pod

2.3 创建一个Pod

我们从Docker Hub上找了个一个dns相关的镜像(即:tutum/dnsutils),来创建一个Pod, 对应的dnsutils.yaml如下

apiVersion: v1
kind: Pod                # k8s资源类型
metadata:                # pod元数据
 name: dnsutil-pod       # pod的名称
spec:                    # pod规格
 containers:
 - image: tutum/dnsutils # 创建容器所用的镜像
   name: dnsutil         # 容器的名称
   command: ["sleep", "infinity"]

图5

3 Label

3.1 什么是Label

Label(标签)是一个可以附加到K8s对象(比如Pod,Woker Node等)上的任意key-value对(一个Label就是一个key/value对,每个资源可以拥有多个Label, 并且可以随时进行添加和修改), 然后通过Selector(标签选择器)来选择具有相应Label的K8s对象。

3.1 为什么需要Label

Label使用户能够以松散耦合的方式将他们自己的组织结构映射到系统对象,而无需客户端存储这些映射(即:如下图所示,在同一个K8s集群中运行着6个Pod, 其中在Pod1/Pod2/Pod3运行着App1,在Pod4/Pod5中运行着App2,我们通过给Pod1/Pod2/Pod3打上“紫色的标签”来标识这写是运行着App1的Pod,通过给Pod4/Pod5打上“蓝色的标签”来标识运行着App2的Pod集合;此时如果我们想找出所有运行着App1的Pod,我们通过Selector(标签选择器)来筛选贴着“紫色的标签”的Pod就行了)。

图6

3.1 创建一个Label

我们可以在2.3节创建的dnsutil-pod添加标签app=dnsutil,然后通过kubectl get 命令行查看标签为app=dnsutil的Pod

图7

4 ReplicaSet

4.1 什么是ReplicaSet

4.2 为什么需要ReplicaSet

4.3 创建一个ReplicaSet

replicaset.yaml文件内容如下:

apiVersion: apps/v1
kind: ReplicaSet 
metadata:
 name: dnsutil-rs    # replica set 名字
spec: 
 replicas: 2         # 期望pod的数量
 selector:
   matchLabels:      # 操作label app=dnsutil的pod
    app: dnsutil 
 template:           # 创建新pod所用的pod模版 
   metadata:
     labels:
       app: dnsutil
   spec:
     containers:
     - name: dnsutil
       image: tutum/dnsutils
       command: ["sleep", "infinity"]

需要指出的是,由于我们在3.1节创建了一个Label为app=dnsutil的Pod,并且我们期望的Pod数量是2,所以此时ReplicaSet(name: dnsutil-rs)只需要再创建一个新的Pod即可以满足期望的Pod数量。

图9

5 Service

5.1 什么是Service

图10

5.2 为什么需要Service

5.3 集群内部Pod间通信

Service通过标签选择器来指定哪些Pod属于同一个组(图中Service(test-svc)选择所有贴着“紫色的标签“的Pod),然后将连接到该Service的客户端链接通过负载均衡路由到某一个后端Pod。

图11

5.3.1 创建一个Service

apiVersion: v1
kind: Service
metadata:
  name: test-svc
spec:
  ports:
  - port: 80         # 该服务的可用端口
    targetPort: 8080 # 服务将连接转发到的容器端口
  selector:          # label app=testing的pod属于该服务
    app: testing
apiVersion: apps/v1
kind: ReplicaSet
metadata:
 name: fqdn-test
spec:
 replicas: 3
 selector:
   matchLabels:
    app: testing   # 操作label app=testing的Pod
 template:
   metadata:
     labels:
       app: testing
   spec:
     containers:
     - name: nodejs
       image: qinchaowhut/allen:v1

图12

5.4 集群内部Pod暴露给外部客户端

接下来我们介绍一下集群外部客户端通过NodePort和LoadBalancer Service访问集群内部的服务。

5.4.1 NodePort Service

在每个Worker Node上开放静态端口(所有Woker Node使用同一个端口号),外部客户端可以直接通过任一Woker Node 的IP和静态端口访问后端 Pod。

图13

5.4.2 LoadBalancer Service

LoadBalancer服务是NodePort服务的一种扩展,使用云平台的负载均衡器向外部公开 Service(其中负载均衡器将外部客户端的请求重定向到Worker Node的静态端口)。

图14

5.5 Headless Service

5.5.1创建一个Headless Service

apiVersion: v1
kind: Service
metadata:
  name: test-svc-headless
spec:
  clusterIP: None   # 注意,这里需要设置为NONE
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: testing

图15

图16

6 Deployment

6.1 什么是Deployment

Deployment用于声明式地定义、部署和更新应用程序(Deployment由ReplicaSet组成(1:N),并且由ReplicaSet来创建和管理Pod)。

6.2 创建一个Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: testqc
spec:
  replicas: 3
  template:
    metadata:
      name: allen
      labels:
        app: testing
    spec:
      containers:
      - image: qinchaowhut/allen:v1
        name: nodejs
        imagePullPolicy: IfNotPresent
  selector:
    matchLabels:
      app: testing

图17

apiVersion: v1
kind: Service
metadata:
  name: allen-loadbalancer
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: testing

图18

图19

6.2 Deployment的升级策略

6.3 触发升级

触发条件:只要deployment中定义的pod模板发生变更,则会触发自动升级。

图20

图21

图22

图23

6.5 控制RollingUpdate速率

在Deployment的滚动升级期间,我门可以通过指定maxUnavailable和maxSurge来控制滚动更新过程。

在我们测试环境中,我们将6.2节中的Deployment描述文件修改如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: testqc
spec:
  replicas: 3              # 期望副本数量
  strategy:
    type: RollingUpdate    # 滚动更新
    rollingUpdate:
      maxSurge: 30%        # 3*30%=1(向上取整)
      maxUnavailable: 15%  # 3*15%=0(向下取整)
  minReadySeconds: 180     # 减慢升级的速率,便于我们观察滚动升级过程
  template:
    metadata:
      name: allen
      labels:
        app: testing
    spec:
      containers:
      - image: qinchaowhut/allen:v1
        name: nodejs
        imagePullPolicy: IfNotPresent
  selector:
    matchLabels:
      app: testing

具体的升级过程如下:

图24

图25

图26

图27

图28

图29

7 参考资料