kubernetes入门

一.导言

随着容器技术的发展,软件界对容器管理的需求越来越迫切,于是出现了一些kubernetes(即k8s),docker swarm 等容器管理软件。同时k8s等服务编排软件也让微服务变得可行,快速扩容缩容,自动处理网络配置等特性也让k8s如火如荼。

k8s能做什么?

  • 服务发现和负载均衡,使用dns或者ip对外暴露容器服务,并提供负载均衡
  • 存储管理,多种存储选择
  • 拟态扩容缩容,根据需求扩容,缩容,并且k8s会尽力达到desired state
  • 自动装箱,比如配置每个容器能使用的CPU和RAM资源,k8s将容器分配到合适的节点以最大化利用系统资源
  • 自动处理故障,当容器失效时,能快速处理,并且不会对客户端有影响
  • 配置和秘钥管理

二.k8s架构及相关概念

control plane:控制台

kube-apiserver: k8s的核心api服务,一般需要做横向扩展

etcd: 提供一致性和高可用的的键值存储,k8s用来存储集群数据。etcd是一款用go语言编写的分布式kv存储,基于raft算法,能提供更稳定的高负载稳定读写能力。

kube-scheduler: 为未分配节点的pod寻找合适的节点

kube-controller-manager: 包括以下controller

  •   node controller: 监视节点下线
  •   job-controller: 监视Job 运行状况
  •   EndpointSlice controller: 即端点列表控制器,为Service 和 pod 提供连接

cloud-controller-manager: 云服务控制管理

node:节点,对应物理机或者虚拟机

kubelet: 运行在节点中的agent,确保容器运行在pod中

kube-proxy: 运行在节点中的网络代理,为Servcie提供支持

pod: k8s 抽象出来的的管理单元,包括一个或者多个容器,共享存储,网络,端口等资源

volume: 存储单元抽象

container:容器,比如docker

Deployment:部署,描述部署的容器,复制等信息,一个典型的Deployment如下

    apiVersion: apps/v1 (版本)
	kind: Deployment (对象类型)
	metadata: (元数据)
	  name: nginx-deployment (name, UIDs)
	spec: (目标状态)
	  selector:
	    matchLabels:
	      app: nginx
	  replicas: 2 # tells deployment to run 2 pods matching the template
	  template:
	    metadata:
	      labels: (labels and selector)
	        app: nginx
	    spec:
	      containers:
	      - name: nginx
	        image: nginx:1.14.2
	        ports:
	        - containerPort: 80

Service:基于pod创建对外或者对内网络服务

三.构建无状态服务

无状态服务:服务不依赖自身的状态,实例的状态数据可以维护在内存中。

构建步骤如下:

   0.笔者这里使用minikube进行测试,先启动minikube   

minikube start
minikube dashboard # 启动后台管理界面

1.执行部署

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: load-balancer-example
  name: hello-world
spec:
  replicas: 5
  selector:
    matchLabels:
      app.kubernetes.io/name: load-balancer-example
  template:
    metadata:
      labels:
        app.kubernetes.io/name: load-balancer-example
    spec:
      containers:
      - image: gcr.io/google-samples/node-hello:1.0
        name: hello-world
        ports:
        - containerPort: 8080
kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml

2.查看部署信息

kubectl get deployments hello-world
kubectl describe deployments hello-world

NAME          READY   UP-TO-DATE   AVAILABLE   AGE
hello-world   5/5     5            5           12m

3.查看副本集

这里我们创建了五个副本

kubectl get replicasets
kubectl describe replicasets

NAME                         DESIRED   CURRENT   READY   AGE
hello-world-644f58f5f4       5         5         5       12m

4.创建Service暴露部署

kubectl expose deployment hello-world --type=LoadBalancer --name=my-service # LoadBalancer表示使用负载均衡的方式

5.查看Service

kubectl get services my-service

NAME         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
my-service   LoadBalancer   10.102.184.247   <pending>     8080:31755/TCP   3s

6.查看Service详细信息

kubectl describe services my-service
Name:                     my-service
Namespace:                default
Labels:                   app.kubernetes.io/name=load-balancer-example
Annotations:              <none>
Selector:                 app.kubernetes.io/name=load-balancer-example
Type:                     LoadBalancer
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.102.184.247
IPs:                      10.102.184.247
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  31755/TCP
Endpoints:                10.244.0.87:8080,10.244.0.88:8080,10.244.0.89:8080 + 2 more... # 端点
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none

7.查看pod对应的端点

kubectl get pods --output=wide
NAME                               READY   STATUS      RESTARTS        AGE     IP            NODE       NOMINATED NODE   READINESS GATES
hello-world-644f58f5f4-2slc4       1/1     Running     0               8m46s   10.244.0.91   minikube   <none>           <none>
hello-world-644f58f5f4-jjf6w       1/1     Running     0               8m46s   10.244.0.88   minikube   <none>           <none>
hello-world-644f58f5f4-mzd5x       1/1     Running     0               8m46s   10.244.0.90   minikube   <none>           <none>
hello-world-644f58f5f4-t6cmj       1/1     Running     0               8m46s   10.244.0.89   minikube   <none>           <none>
hello-world-644f58f5f4-xlvtr       1/1     Running     0               8m46s   10.244.0.87   minikube   <none>           <none>

8.访问服务

使用 curl http://<external-ip>:<port> 进行访问。

<external-ip> 这里指代LoadBalancer Ingress地址,许多厂商开发了各种网关和k8s集成。

<port> 指代Service暴露的端口。

如果是minikube,直接启动即可

➜  k8s minikube service my-service
|-----------|------------|-------------|---------------------------|
| NAMESPACE |    NAME    | TARGET PORT |            URL            |
|-----------|------------|-------------|---------------------------|
| default   | my-service |        8080 | http://192.168.49.2:31755 |
|-----------|------------|-------------|---------------------------|
🏃  Starting tunnel for service my-service.
|-----------|------------|-------------|------------------------|
| NAMESPACE |    NAME    | TARGET PORT |          URL           |
|-----------|------------|-------------|------------------------|
| default   | my-service |             | http://127.0.0.1:53820 |
|-----------|------------|-------------|------------------------|
🎉  正通过默认浏览器打开服务 default/my-service...
❗  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.

三.构建有状态服务

有状态服务 · 服务本身依赖或者存在局部的状态数据,这些数据需要自身持久化或者可以通过其他节点恢复。

  1.添加自定义配置文件,存储mysql密码

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
  literals:
  - password=YOUR_PASSWORD
EOF

  2.编写部署mysql 和 WordPress文件

  mysql部署文件 application/wordpress/mysql-deployment.yaml:

apiVersion: v1
kind: Service # 部署服务
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim # 指定持久化存储
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment # mysql部署
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass # 使用之前定义的秘钥
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql # 将该路径的存储映射到mysql-pv-claim
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

WordPress 部署文件:application/wordpress/wordpress-deployment.yaml

apiVersion: v1
kind: Service # 暴露服务
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim # 指定持久化存储
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html # 存储路径映射
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim

  将以上文件写入到kustomization.yaml中

cat <<EOF >>./kustomization.yaml
resources:
  - mysql-deployment.yaml
  - wordpress-deployment.yaml
EOF

  3.执行部署

kubectl apply -k ./ #确保上述文件在当前目录下

  查看秘钥:

➜  k8s kubectl get secrets
NAME                    TYPE     DATA   AGE
mysql-pass-kkcc2b926b   Opaque   1      3d22h

  查看PersistentVolume:

➜  k8s kubectl get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pv-claim   Bound    pvc-456c2492-32bd-4d15-9753-c3ad1034c38f   20Gi       RWO            standard       3d22h
wp-pv-claim      Bound    pvc-78d63fcd-9c75-4320-97d6-4498d2915707   20Gi       RWO            standard       3d22h

  查看pod:

➜  k8s kubectl get pods
NAME                               READY   STATUS      RESTARTS      AGE
wordpress-7fdfc976b9-4tx6d         1/1     Running     0             16s
wordpress-mysql-6987d65455-f44dz   1/1     Running     0             16s

  查看Service:

➜  k8s kubectl get services wordpress                
NAME        TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
wordpress   LoadBalancer   10.101.95.45   <pending>     80:31798/TCP   3d22h

  运行服务,访问 http://127.0.0.1:52503/ 即可看到服务地址

➜  k8s minikube service wordpress --url
http://127.0.0.1:52503
❗  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.

四.网络模型

k8s给集群里面的每个pod分配集群内 IP地址,这个ip仅仅限制在集群内部使用。

  • pod之间可以互相访问,不依赖NAT(Network Address Translation)
  • 节点上的agent(kubelet)可以和其他节点上的pod互相访问

"IP-per-pod" model:同一个pod里面的容器共享网络命名空间,即共享ip地址,mac地址等等。这意味着pod里面的容器可以使用localhost互相访问对方的端口,同时要求容器内的端口不能互相冲突。

  • pod里面的容器使用loopback 互相访问
  • pod之间通过cluster-wide IP 互相访问
  • 可以使用Service暴露服务,方便从集群外部访问。许多厂商开发了各类网关,以支持http 应用,网站,和APIs

五.最佳实践

  • 所有配置文件,比如Deployment, Service 应该进行版本控制,推送到git仓库
  • 先创建Service,然后再创建Deployment,这样pod就能获得Service的相关信息
  • 使用DNS server插件
  • 不要为pod指定地址端口
  • 使用语义化的标签来进行管理应用或者部署,比如{ app.kubernetes.io/name: MyApp, tier: frontend, phase: test, deployment: v3 }

六.CRI 之 docker engine

  1.容器发展史

  2.docker 架构和底层技术

  docker 使用go语言编写,使用namespaces 来隔离workspace (container)。当我们创建一个container,docker创建一系列的namespace来进行隔离。

  docker 使用cgroup来进行资源控制。

  3.docker 中的一些关键概念

  •   每个container只包含一个进程
  •   可以使用docker compose,组合多个container进行管理
  •   docker提供两种持久化方式,volumes(使用卷的方式), bind mounts(挂载)
  •   image是分层的,并且可以缓存
  •   使用Multi-stage builds,只保留最后一阶段的输出

  4.docker最佳实践

  image:

    • 选择合适的base image
    • 使用Multi-stage builds,可以让image变得更小
    • 在共享组件的基础上构建image
    • 对image打标签
    • 在正式环境使用volumes存储,在开发环境使用bind mounts存储
    • 使用CI/CD开发

  dockerfile:

    • 创建无状态的container
    • 使用stdin 创建 Dockerfile
    • 使用.dockerignore排除文件
    • 使用Multi-stage builds
    • 不要安装不必要的包
    • 解耦应用,每个container只运行一个进程
    • 减少layer的数量  

七.总结

本文介绍了k8s的核心架构,和重要相关概念,并且演示了两个典型用例。同时介绍了docker的相关知识。

八.参考

https://docs.docker.com/get-started/

https://kubernetes.io/docs/home/

热门相关:地球第一剑   无限杀路   夫人你马甲又掉了   重生之至尊千金   名门天后:重生国民千金