pod

pause 容器

也叫 Infra 容器

对于 Pod 里的容器 A 和容器 B 来说:

  • 它们可以直接使用 localhost 进行通信;
  • 它们看到的网络设备跟 Infra 容器看到的完全一样;
  • 一个 Pod 只有一个 IP 地址,也就是这个 Pod 的 Network Namespace 对应的 IP 地址;
  • 当然,其他的所有网络资源,都是一个 Pod 一份,并且被该 Pod 中的所有容器共享;
  • pod 的生命周期只跟 Infra 容器一致,而与容器 A 和 B 无关。

pause容器作用

  • 扮演Pid=1的,回收僵尸进程
  • 基于Linux的namespace的共享

Kubernetes 项目里,Infra 容器一定要占用极少的资源,所以它使用的是一个非常特殊的镜像,叫作:k8s.gcr.io/pause。这个镜像是一个用汇编语言编写的、永远处于“暂停”状态的容器,解压后的大小也只有 100~200 KB 左右。

而在 Infra 容器“Hold 住”Network Namespace 后,用户容器就可以加入到 Infra 容器的 Network Namespace 当中了

多容器进入

1kubectl exec -it xxx -c 容器名 -- sh 

挂载主机目录hostPath

https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: test-pd
 5spec:
 6  containers:
 7  - image: registry.k8s.io/test-webserver
 8    name: test-container
 9    volumeMounts:
10    - mountPath: /test-pd
11      name: test-volume
12  volumes:
13  - name: test-volume
14    hostPath:
15      # 宿主上目录位置
16      path: /data
17      # 此字段为可选
18      type: Directory

pod中的2个容器共享文件夹

同一个pod内的容器都能读写EmptyDir中 文件。常用于临时空间、多容器共享,如日志或者tmp文件需要的临时目录

两个容器分别写入挂载点 volumeMounts

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: myngx
 5spec:
 6  selector:
 7    matchLabels:
 8      app: nginx
 9  replicas: 1
10  template:
11    metadata:
12      labels:
13        app: nginx
14    spec:
15      containers:
16        - name: ngx
17          image: nginx:1.18-alpine
18          imagePullPolicy: IfNotPresent
19          volumeMounts:
20            - name: sharedata
21              mountPath: /data
22        - name: alpine
23          image: alpine:3.12
24          imagePullPolicy: IfNotPresent
25          command: ["sh","-c","echo this is alpine && sleep 36000"]
26          volumeMounts:
27            - name: sharedata
28              mountPath: /data
29      volumes:
30        - name:  sharedata
31          emptyDir: {}

init容器的基本使用、sidecar模式

https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/init-containers/

Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本

Init 容器与普通的容器非常像,除了如下两点:

它们总是运行到完成。

每个都必须在下一个启动之前成功完成。

如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的 restartPolicy 值为 “Never”,Kubernetes 不会重新启动 Pod。

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: javaweb-2
 5spec:
 6  initContainers:
 7    - image: geektime/sample:v2
 8      name: war
 9      command: ["cp", "/sample.war", "/app"]
10      volumeMounts:
11        - mountPath: /app
12          name: app-volume
13  containers:
14    - image: geektime/tomcat:7.0
15      name: tomcat
16      command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
17      volumeMounts:
18        - mountPath: /root/apache-tomcat-7.0.42-v2/webapps
19          name: app-volume
20      ports:
21        - containerPort: 8080
22          hostPort: 8001
23  volumes:
24    - name: app-volume
25      emptyDir: {}

像这样,我们就用一种“组合”方式,解决了 WAR 包与 Tomcat 容器之间耦合关系的问题。

实际上,这个所谓的“组合”操作,正是容器设计模式里最常用的一种模式,它的名字叫:sidecar。

sidecar 指的就是我们可以在一个 Pod 中,启动一个辅助容器,来完成一些独立于主进程(主容器)之外的工作。

在我们的这个应用 Pod 中,Tomcat 容器是我们要使用的主容器,而 WAR 包容器的存在,只是为了给它提供一个 WAR 包而已。所以,我们用 Init Container 的方式优先运行 WAR 包容器,扮演了一个 sidecar 的角色。

资源限制

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: busybox
 5  namespace: dev
 6  labels:
 7    app: busybox
 8spec:
 9  containers:
10    - image: busybox
11      name: busybox
12      imagePullPolicy: IfNotPresent
13      env:
14      - name: app
15        value: busybox
16      # 终端
17      tty: true
18      # 拥有宿主机权限
19      securityContext:
20       privileged: true
21      workingDir: /test
22      command: ["/bin/sh"]
23      args: ["-c","while true; do echo hello;sleep 10; done"]
24      resources:
25        requests:
26          # 100mb
27          memory: "100Mi"
28          # 1核心 = 1000m
29          cpu: "1000m"
30        limits:
31          memory: "200Mi"
32          cpu: "1000m"

网络

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: nginx
 5  namespace: dev
 6  labels:
 7    app: nginx
 8spec:
 9  # hostNetwork: true
10  # 可选值  Default|ClusterFirst|ClusterFirstWithHostNet|None
11  dnsPolicy: "Default"
12  # dns配置
13  dnsConfig:
14    nameservers:
15      - 8.8.8.8
16  #域名映射
17  hostAliases:
18    - ip: 192.168.56.80
19      hostnames:
20        - "foo.local"
21        - "bar.local"
22  containers:
23    - name: nginx
24      image: nginx:1.17.1
25      imagePullPolicy: IfNotPresent
26      ports:
27        - name: nginx-port
28          containerPort: 80
29          protocol: TCP
30          hostPort: 8080 # 如果使用 hostNetwork 则这里不生效

pod健康检查

每个容器三种探针(Probe)

  • 启动探针 一次性成功探针。只要启动成功了

    • kubelet 使用启动探针,来检测应用是否已经启动。如果启动就可以进行后续的探测检 查。慢容器一定指定启动探针。一直在等待启动
    • 启动探针 成功以后就不用了,剩下存活探针和就绪探针持续运行
  • 存活探针

    • kubelet 使用存活探针,来检测容器是否正常存活。(有些容器可能产生死锁【应用程序 在运行,但是无法继续执行后面的步骤】), 如果检测失败就会**重新启动这个容器 **
    • initialDelaySeconds: 3600(长了导致可能应用一段时间不可用) 5(短了陷入无限启动循环)
  • 就绪探针

    • kubelet 使用就绪探针,来检测容器是否准备好了可以接收流量。当一个 Pod 内的所有容器都准备好了,才能把这个 Pod 看作就绪了。用途就是:Service后端负载均衡多个 Pod,如果某个Pod还没就绪,就会从service负载均衡里面剔除

谁利用这些探针探测?

 kubelet会主动按照配置给Pod里面的所有容器发送响应的探测请求

Probe 配置项

https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes

 1exec、httpGet、tcpSocket 【那种方式探测】
 2
 3exec 启动一个命令  返回0 才算成功, 其他算失败
 4    
 5initialDelaySeconds         20  容器启动后指定多少秒后 才开始探测 
 6periodSeconds      每隔多少秒运行 
 7successThreshold   1  探测器在失败后,被视为成功的最小连续成功数。默认值是 1。
 8								存活和启动探针的这个值必须是 1。最小值是 1。  连续成功1次就算成功。  如果是5  那么必须连续成功5次才行
 9
10failureThreshold  2  几次失败才算真失败  
11
12terminationGracePeriodSeconds
13timeoutSeconds   <integer>

拉取私有镜像

创建一个Secret对象来存储认证信息。可以使用以下命令创建一个基于用户名和密码的Secret

1$ kubectl create secret docker-registry mysecret --docker-server=<私有镜像地址> --docker-username=<用户名> --docker-password=<密码> -n=命名空间

将这个Secret应用到Pod配置文件中的imagePullSecrets字段中。示例如下:

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: mypod
 5spec:
 6  containers:
 7    - name: mycontainer
 8      image: <私有镜像地址>/<镜像名称>:<标签>
 9  imagePullSecrets:
10    - name: mysecret

调度

kube-scheduler 给一个 Pod 做调度选择时包含两个步骤:

  • 过滤
  • 打分

Pod 的调度

  • 与节点标签匹配的 nodeSelector
  • 亲和性与反亲和性
  • nodeName 字段

打标签

1kubectl get nodes --show-labels
2kubectl label node `node_name` `key=value`
3kubectl label node `node_name` `key`- # 取消label 

污点(node)、容忍(pod)

https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/taint-and-toleration/

亲和和反亲和

https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/assign-pod-node/

configMap

ConfigMap 是一种 API 对象,用来将非机密性的数据保存到健值对中。使用时可以用作环境变量、命令行参数或者存储卷中的配置文件。

ConfigMap 将您的环境配置信息和 容器镜像 解耦,便于应用配置的修改。当您需要储存机密信息时可以使用 Secret 对象。

使用的四个场景

1、 容器 entrypoint 的命令行参数

2、 容器的环境变量

3、 映射成文件

4、 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap

获取列表

1kubectl get cm

容器环境变量引用

 1apiVersion: v1
 2kind: ConfigMap
 3metadata:
 4  name: mycm
 5data:
 6  # 每一个键对应一个简单的值,以字符串的形式体现
 7  username: "crmao"
 8  userage: "30"
 9  # 多行模式,下面只是字符串
10  user.info: |
11    name=mao
12    age=19    
 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: myngx
 5spec:
 6  selector:
 7    matchLabels:
 8      app: nginx
 9  replicas: 1
10  template:
11    metadata:
12      labels:
13        app: nginx
14    spec:
15      containers:
16        - name: ngx
17          image: nginx:1.18-alpine
18          imagePullPolicy: IfNotPresent
19          env:
20            - name: TEST
21              value: testvalue
22            - name: USERNAME
23              valueFrom:
24                configMapKeyRef:
25                  name: mycm           #  ConfigMap的名称
26                  key: username # 需要取值的键

映射成容器中的单文件

https://kubernetes.io/zh-cn/docs/concepts/configuration/configmap/

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: myngx
 5spec:
 6  selector:
 7    matchLabels:
 8      app: nginx
 9  replicas: 1
10  template:
11    metadata:
12      labels:
13        app: nginx
14    spec:
15      containers:
16        - name: ngx
17          image: nginx:1.18-alpine
18          imagePullPolicy: IfNotPresent
19          volumeMounts:
20            - name: cmdata
21              mountPath: /data
22          env:
23            - name: TEST
24              value: testvalue
25            - name: USERNAME
26              valueFrom:
27                configMapKeyRef:
28                  name: mycm           #  ConfigMap的名称
29                  key: username # 需要取值的键
30      volumes:
31        - name: cmdata
32          configMap:
33            name: mycm
34            items:
35              - key: user.info
36                path: user.txt   # 那么在ngx容器中 /data目录下会存在 user.txt文件  内容是 configmap 键为user.info 的值

subpath

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: myngx
 5spec:
 6  selector:
 7    matchLabels:
 8      app: nginx
 9  replicas: 1
10  template:
11    metadata:
12      labels:
13        app: nginx
14    spec:
15      containers:
16        - name: ngx
17          image: nginx:1.18-alpine
18          imagePullPolicy: IfNotPresent
19          volumeMounts:
20            - name: cmdata
21              mountPath: /data/user.txt
22              subPath: user.info
23          env:
24            - name: TEST
25              value: testvalue
26            - name: USERNAME
27              valueFrom:
28                configMapKeyRef:
29                  name: mycm           #  ConfigMap的名称
30                  key: username # 需要取值的键
31      volumes:
32        - name: cmdata
33          configMap:
34            defaultMode: 0655
35            name: mycm
36#            items:
37#              - key: user.info
38#                path: user.txt

k8s内置类型

Kubernetes提供若干种内置的类型,用于一些常见的使用场景。 针对这些类型,Kubernetes所执行的合法性检查操作以及对其所实施的限制各不相同。

内置类型 用法
Opaque 用户定义的任意数据
kubernetes.io/service-account-token 服务账号令牌
kubernetes.io/dockercfg ~/.dockercfg 文件的序列化形式
kubernetes.io/dockerconfigjson ~/.docker/config.json 文件的序列化形式
kubernetes.io/basic-auth 用于基本身份认证的凭据
kubernetes.io/ssh-auth 用于 SSH 身份认证的凭据
kubernetes.io/tls 用于 TLS 客户端或者服务器端的数据
bootstrap.kubernetes.io/token 启动引导令牌数据

secret

Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。 参阅 Secret 设计文档 获取更多详细信息。

Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 用户可以创建 Secret,同时系统也创建了一些 Secret。

敏感、少量 ,安全和灵活

类型 : Opaque 用户自定义的类型

https://www.kubernetes.org.cn/secret

1apiVersion: v1
2kind: Secret
3metadata:
4  name: mysecret
5type: Opaque
6data:
7  user: c2hlbnlp
8  pass: MTIzNDU2
1echo -n "123456" | base64
2echo -n "MTIzNDU2"  | base64 -d

存储卷管理

EmptyDir

删除Pod时,emptyDir数据同步消失

 1# 缓存数据,可以让多个容器共享数据
 2# 删除Pod时,emptyDir数据同步消失
 3# 定义initContainer->下载数据到emptyDir->在container挂载emptyDir,能看数据共享
 4apiVersion: v1
 5kind: Pod
 6metadata:
 7  name: busybox
 8  namespace: dev
 9  labels:
10    app: busybox
11spec:
12  nodeName: k8snode1
13  initContainers:
14    - name: download
15      image: busybox
16      command: ['/bin/sh','-c','echo hello > /workdir/index.html']
17      volumeMounts:
18        - name: workdir
19          mountPath: /workdir
20  containers:
21    - name: web
22      image: nginx
23      ports:
24        - containerPort: 80
25          hostPort: 8080
26      volumeMounts:
27        - name: workdir
28          mountPath: /usr/share/nginx/html
29  volumes:
30    - name: workdir
31      emptyDir: {}
1root@k8smaster:~# curl http://192.168.56.81:8080
2hello

hostPath

挂载到宿主机

type: DirectoryOrCreate | Directory | File | FileOrCreate | Socket | ""

Directory : 没有目录会会报错

 1# docker -v 参数等效
 2apiVersion: v1
 3kind: Pod
 4metadata:
 5  name: busybox
 6  namespace: dev
 7  labels:
 8    app: busybox
 9spec:
10  nodeName: k8snode1
11  containers:
12    - name: web
13      image: nginx
14      ports:
15        - containerPort: 80
16          hostPort: 8080
17      volumeMounts:
18        - name: workdir
19          mountPath: /usr/share/nginx/html
20  volumes:
21    - name: workdir
22      hostPath:
23        # DirectoryOrCreate | Directory | File | FileOrCreate | Socket | ""
24        type: DirectoryOrCreate
25        path: /workdir2

在k8snode1机器上查看

1docker inspect `CONTAINER ID`

downward

作用: 将pod的定义信息(metadata信息)挂载到容器内

 1# 将pod的定义信息(metadata信息)挂载到容器内
 2apiVersion: v1
 3kind: Pod
 4metadata:
 5  name: busybox
 6  namespace: dev
 7  labels:
 8    app: busybox
 9spec:
10  nodeName: k8snode1
11  containers:
12    - name: web
13      image: nginx
14      ports:
15        - containerPort: 80
16          hostPort: 8080
17      env:
18        - name: MY_NODE_NAME
19          valueFrom:
20            fieldRef:
21              fieldPath: spec.nodeName
22              # podIP nodeIP sa
23      volumeMounts:
24        - name: workdir
25          mountPath: /usr/share/nginx/html
26  volumes:
27    - name: workdir
28      downwardAPI:
29        items:
30          - path: podname.html
31            fieldRef:
32              fieldPath: metadata.name

查看结果

1kubectl exec -it busybox -n dev -- sh
2printenv 
3# 有 MY_NODE_NAME=k8snode1 
4root@k8smaster:~# curl http://192.168.56.81:8080/podname.html
5busybox

configmap

1apiVersion: v1
2kind: ConfigMap
3metadata:
4  name: testcm
5  namespace: test
6data:
7  db_name: mysql
8  db_name1: mysql1
 1# 将configMap的所有的数据挂载到pod的容器内
 2apiVersion: v1
 3kind: Pod
 4metadata:
 5  name: busybox
 6  namespace: dev
 7  labels:
 8    app: busybox
 9spec:
10  nodeName: k8snode1
11  containers:
12    - name: web
13      image: nginx
14      imagePullPolicy: IfNotPresent
15      ports:
16        - containerPort: 80
17          hostPort: 8080
18      volumeMounts:
19        - name: workdir
20          mountPath: /usr/share/nginx/html
21  volumes:
22    - name: workdir
23      configMap:
24        name: testcm
25        optional: true

进入pod,/usr/share/nginx/html下会多出个文件对应key的名称。

secret

跟configmap 类似

进入pod,/usr/share/nginx/html下会多出个文件对应key的名称。

 1apiVersion: v1
 2kind: Secret
 3metadata:
 4  name: testsec
 5  namespace: dev
 6  labels:
 7    secret: testsec
 8type: Opaque
 9data:
10  db_name: dGVzdGRiMgo=
11  db_host: MTI3LjAuMC4yCg==
12---
13# 将configMap的所有的数据挂载到pod的容器内
14apiVersion: v1
15kind: Pod
16metadata:
17  name: busybox
18  namespace: dev
19  labels:
20    app: busybox
21spec:
22  nodeName: k8snode1
23  containers:
24    - name: web
25      image: nginx
26      imagePullPolicy: IfNotPresent
27      ports:
28        - containerPort: 80
29          hostPort: 8080
30      volumeMounts:
31        - name: workdir
32          mountPath: /usr/share/nginx/html
33  volumes:
34    - name: workdir
35      secret:
36        secretName: testsec
37        optional: true

nfs

nfs安装

1sudo apt -y install nfs-kernel-server # nfs 服务端 安装到集群某一台即可
2sudo apt-get install nfs-common # nfs 客户端 ,每个节点都执行

配置 NFS 访问共享目录

 1# 在k8snode1上执行
 2sudo mkdir -p /nfs/share
 3sudo chmod -R 666 /nfs/share
 4sudo vim /etc/exports
 5# 加上一行
 6/nfs/share 192.168.56.81/24(rw,sync,no_subtree_check,no_root_squash,insecure)
 7sudo exportfs -ra # 需要用 exportfs -ra 通知 NFS,让配置生效
 8sudo exportfs -v # exportfs -v 验证效果:
 9
10
11# 启动nfs 
12sudo systemctl start  nfs-server
13sudo systemctl enable nfs-server
14sudo systemctl status nfs-server
15
16# showmount 来检查 NFS 的网络挂载情况:
17sudo showmount -e 127.0.0.1
18#Export list for 127.0.0.1:
19#/nfs/share 192.168.56.81/24

k8smaster节点执行

1mkdir -p /tmp/test
2sudo mount -t nfs 192.168.56.81:/nfs/share /tmp/test
3sudo touch /tmp/test/x.yaml
4# 去nfs 服务器验证 /nfs/share 下多出了一个x.yaml 

有点问题

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: busybox1
 5  namespace: dev
 6  labels:
 7    app: busybox1
 8spec:
 9  nodeName: k8snode1
10  containers:
11    - name: web
12      image: nginx
13      imagePullPolicy: IfNotPresent
14      ports:
15        - containerPort: 80
16          hostPort: 8080
17      volumeMounts:
18        - name: workdir1
19          mountPath: /usr/share/nginx/html
20  volumes:
21    - name: workdir1
22      nfs:
23        server: 192.168.56.81
24        path: /nfs/share

pv,pvc

手动创建 /nfs/share/pv01 目录

这里pvc 是通过标签 关联到了pv 运行起来后,进入pod ,touch index.html, 对应到k8snode1 ,/nfs/share/pv01 也会多出这个文件,是互通的

pvc 使用来归类的 一个pv 对应一个pvc (实践) 。 pvc这里 跟 ingress class 很像,

 1apiVersion: v1
 2kind: PersistentVolume
 3metadata:
 4  name: nfs-pv01
 5  namespace: dev
 6  labels:
 7    pv: nfs-pv01
 8spec:
 9  capacity:
10    storage: 1Gi
11  accessModes:
12    - ReadWriteOnce
13  #Recycle 删除Pvc同步删除PV | Retain
14  persistentVolumeReclaimPolicy: Retain
15  nfs:
16    path: /nfs/share/pv01
17    server: 192.168.56.81
18    readOnly: false
19---
20apiVersion: v1
21kind: PersistentVolumeClaim
22metadata:
23  name: nfs-pvc01
24  namespace: dev
25  labels:
26    pv: nfs-pvc01
27spec:
28  resources:
29    requests:
30      storage: 500Mi
31  accessModes:
32    - ReadWriteOnce
33  selector:
34    matchLabels:
35      pv: nfs-pv01
36---
37apiVersion: v1
38kind: Pod
39metadata:
40  name: web
41  namespace: dev
42  labels:
43    app: web
44spec:
45  nodeName: k8snode1
46  containers:
47    - name: web
48      image: nginx
49      imagePullPolicy: IfNotPresent
50      ports:
51        - containerPort: 80
52          hostPort: 8080
53      volumeMounts:
54        - name: workdir
55          mountPath: /usr/share/nginx/html
56  volumes:
57    - name: workdir
58      persistentVolumeClaim:
59        claimName: nfs-pvc01
1kubectl get pv ,pvc -n dev

动态存储卷

可以用 StorageClass 绑定一个 Provisioner 对象,而这个 Provisioner 就是一个能够自动管理存储、创建 PV 的应用,代替了原来系统管理员的手工劳动。

NFS Provisoner 安装

 1helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
 2 helm pull nfs-subdir-external-provisioner/nfs-subdir-external-provisioner
 3 tar zxvf nfs-subdir-external-provisioner-4.0.18.tgz
 4 cd nfs-subdir-external-provisioner/
 5 vim values.yaml
 6 # 修改 nfs地址及 镜像仓库(不然拉不下来)
 7 #image:
 8  #repository: dyrnq/nfs-subdir-external-provisioner
 9  
10helm  install nfs-subdir-external-provisioner . -n kube-system --debug
11helm list -n kube-system
12kubectl get pod -n kube-system | grep nfs

pod指定pvc,pvc指定StorageClass,StorageClass通过 provisioner 自动创建管理pv。

 1apiVersion: storage.k8s.io/v1
 2kind: StorageClass
 3metadata:
 4  name: nfs-storage
 5  namespace: dev
 6provisioner: cluster.local/nfs-subdir-external-provisioner
 7#parameters:
 8#  server: nfs-server.example.com
 9#  path: /share
10#  readOnly: "false"
11mountOptions:
12  - nfsvers=4
13---
14apiVersion: v1
15kind: PersistentVolumeClaim
16metadata:
17  name: nfs-pvc02
18  namespace: dev
19  labels:
20    pvc: nfs-pvc02
21spec:
22  resources:
23    requests:
24      storage: 500Mi
25  accessModes:
26    - ReadWriteOnce
27  storageClassName: nfs-storage
28#  selector:
29#    matchLabels:
30#      pv: nfs-pv01
31---
32apiVersion: v1
33kind: Pod
34metadata:
35  name: web
36  namespace: dev
37  labels:
38    app: web
39spec:
40  nodeName: k8snode1
41  containers:
42    - name: web
43      image: nginx
44      imagePullPolicy: IfNotPresent
45      ports:
46        - containerPort: 80
47          hostPort: 8080
48      volumeMounts:
49        - name: workdir
50          mountPath: /usr/share/nginx/html
51  volumes:
52    - name: workdir
53      persistentVolumeClaim:
54        claimName: nfs-pvc02

PersistentVolume(old)

PersistentVolume:怎么解决数据持久化的难题?

作为存储的抽象,PV 实际上就是一些存储设备、文件系统,比如 Ceph、GlusterFS、NFS,甚至是本地磁盘,管理它们已经超出了 Kubernetes 的能力范围,所以,一般会由系统管理员单独维护,然后再在 Kubernetes 里创建对应的 PV。 要注意的是,PV 属于集群的系统资源,是和 Node 平级的一种对象,Pod 对它没有管理权,只有使用权。

PersistentVolumeClaim,简称 PVC,从名字上看比较好理解,就是用来向 Kubernetes 申请存储资源的。PVC 是给 Pod 使用的对象,它相当于是 Pod 的代理,代表 Pod 向系统申请 PV。一旦资源申请成功,Kubernetes 就会把 PV 和 PVC 关联在一起,这个动作叫做“绑定”(bind)。 但是,系统里的存储资源非常多,如果要 PVC 去直接遍历查找合适的 PV 也很麻烦,所以就要用到 StorageClass。

StorageClass 这个是为了分类,找合适的pv 。

https://github.com/cr-mao/develop/tree/main/k8s/pv

1kubectl apply -f host-path-pv.yml
2kubectl get pv
3
4kubectl apply -f host-path-pvc.yml
5kubectl get pvc
6
7kubectl apply -f host-pvc-pod.yml

服务发现

pod直接 hostPort

我这里只会调度到k8snode1这个节点 http://192.168.56.81:30080

 1apiVersion: v1
 2kind: Pod
 3
 4metadata:
 5  name: web
 6  namespace: dev
 7  labels:
 8    app: web
 9
10spec:
11  containers:
12    - name: web
13      image: nginx
14      imagePullPolicy: IfNotPresent
15      ports:
16        - name: port0
17          containerPort: 80
18          hostPort: 30080

基于service hostport

 1apiVersion: v1
 2kind: Pod
 3
 4metadata:
 5  name: web
 6  namespace: dev
 7  labels:
 8    app: web
 9
10spec:
11  containers:
12    - name: web
13      image: nginx
14      imagePullPolicy: IfNotPresent
15      ports:
16        - name: port0
17          containerPort: 80
18---
19apiVersion: v1
20kind: Service
21metadata:
22  name: svc-web
23  namespace: dev
24spec:
25  # ClusterIP | LoadBalancer |
26  type: NodePort
27  #  clusterIP: None
28  selector:
29    app: web
30  ports:
31    - name: http
32      port: 80 # service port
33      targetPort: 80 # 容器nginx 的port
34      nodePort: 30080 #暴露到node的port

loadBalancer

基于这个实现 https://github.com/metallb/metallb

https://metallb.universe.tf/installation/

开启ipvs

1helm repo add metallb https://metallb.github.io/metallb
2helm pull metallb/metallb
3tar zxvf metallb-0.14.3.tgz
4
5cd metallb 
6
7 helm install metallb . -n metallb-system --create-namespace --debug
 1apiVersion: v1
 2kind: Service
 3metadata:
 4  name: svc-web-lb
 5  namespace: test
 6spec:
 7  # ClusterIP | LoadBalancer |
 8  #vip -> real cluster node ip(speaker)
 9  type: LoadBalancer
10  #  clusterIP: None
11  selector:
12    app: web
13  ports:
14    - name: http
15      port: 80
16      targetPort: 80
17---
18# 我的网络有问题,拉不下来
19apiVersion: metallb.io/v1beta1
20kind: IPAddressPool
21metadata:
22  name: kubeimooc-ippool
23  namespace: metallb-system
24spec:
25  addresses:
26    - 192.168.56.81/32

ingress controller traefik 安装

1kubectl create ns traefik-system

rbac

 1kind: ClusterRole
 2apiVersion: rbac.authorization.k8s.io/v1
 3metadata:
 4  name: traefik-role
 5  namespace: traefik-system
 6rules:
 7  - apiGroups:
 8      - ""
 9    resources:
10      - services
11      - endpoints
12      - secrets
13    verbs:
14      - get
15      - list
16      - watch
17  - apiGroups:
18      - extensions
19      - networking.k8s.io
20    resources:
21      - ingresses
22      - ingressclasses
23    verbs:
24      - get
25      - list
26      - watch
27  - apiGroups:
28      - extensions
29      - networking.k8s.io
30    resources:
31      - ingresses/status
32    verbs:
33      - update
34---
35apiVersion: v1
36kind: ServiceAccount
37metadata:
38  name: traefik-account
39  namespace: traefik-system
40---
41kind: ClusterRoleBinding
42apiVersion: rbac.authorization.k8s.io/v1
43metadata:
44  name: traefik-role-binding
45  namespace: traefik-system
46roleRef:
47  apiGroup: rbac.authorization.k8s.io
48  kind: ClusterRole
49  name: traefik-role
50subjects:
51  - kind: ServiceAccount
52    name: traefik-account
53    namespace: traefik-system

通过daemonset的方式安装traefik

 1kind: DaemonSet
 2apiVersion: apps/v1
 3metadata:
 4  name: traefik-deployment
 5  namespace: traefik-system
 6  labels:
 7    app: traefik
 8
 9spec:
10#  replicas: 1
11  selector:
12    matchLabels:
13      app: traefik
14  template:
15    metadata:
16      labels:
17        app: traefik
18    spec:
19      serviceAccountName: traefik-account
20      containers:
21        - name: traefik
22          image: traefik:v2.10
23          imagePullPolicy: IfNotPresent
24          args:
25            - --api.insecure
26            - --providers.kubernetesingress
27          ports:
28            - name: web
29              containerPort: 80
30              hostPort: 80
31            - name: dashboard
32              containerPort: 8080
33              hostPort: 8080

dashboard界面 http://192.168.56.81:8080/

ingress

这里用的是k8s 提供的ingress

一个web的例子

 1apiVersion: v1
 2kind: Pod
 3
 4metadata:
 5  name: web
 6  namespace: dev
 7  labels:
 8    app: web
 9
10spec:
11  containers:
12    - name: web
13      image: nginx
14      imagePullPolicy: IfNotPresent
15      ports:
16        - name: port0
17          containerPort: 80
18---
19apiVersion: v1
20kind: Service
21metadata:
22  name: svc-web
23  namespace: dev
24spec:
25  # ClusterIP | LoadBalancer |
26  type: NodePort
27  #  clusterIP: None
28  selector:
29    app: web
30  ports:
31    - name: http
32      port: 80 # service port
33      targetPort: 80 # 容器nginx 的port
34      # nodePort: 30080 #暴露到node的port
35
36---
37apiVersion: networking.k8s.io/v1
38kind: Ingress
39metadata:
40  name: web-ingress
41  namespace: dev
42  annotations:
43    nginx.ingress.kubernetes.io/rewrite-target: /
44spec:
45  #  ingressClassName: nginx-example
46  rules:
47    - host: "foo.bar.com"
48      http:
49        paths:
50          - path: /
51            pathType: Prefix
52            backend:
53              service:
54                name: svc-web
55                port:
56                  number: 80

本机mac /etc/hosts 添加一行

1 192.168.56.81  foo.bar.com

traefik ingressroute

先把上面的traefik给卸载了。

https://doc.traefik.io/traefik/providers/kubernetes-crd/

Installing Resource Definition and RBAC,在上面增加了crd 和rbac的内容。 以及增加了 providers.kubernetescrd的监听

cd https://github.com/cr-mao/develop/tree/main/k8s/k8s_use/discovery/traefik-advanced

1kubectl apply -f . 

把之前的svc,pod 先删了,再看效果(其实没这个必要)

 1apiVersion: v1
 2kind: Pod
 3
 4metadata:
 5  name: web
 6  namespace: dev
 7  labels:
 8    app: web
 9
10spec:
11  containers:
12    - name: web
13      image: nginx
14      imagePullPolicy: IfNotPresent
15      ports:
16        - name: port0
17          containerPort: 80
18---
19apiVersion: v1
20kind: Service
21metadata:
22  name: svc-web
23  namespace: dev
24spec:
25  # ClusterIP | LoadBalancer |
26  type: NodePort
27  #  clusterIP: None
28  selector:
29    app: web
30  ports:
31    - name: http
32      port: 80 # service port
33      targetPort: 80 # 容器nginx 的port
34      # nodePort: 30080 #暴露到node的port
35
36---
37apiVersion: traefik.io/v1alpha1
38kind: IngressRoute
39metadata:
40  name: web-ingressroute
41  namespace: dev
42spec:
43  entryPoints:
44    - http
45  routes:
46    - match: Host(`foo.bar.cn`) && PathPrefix(`/`)
47      kind: Rule
48      services:
49        - name: svc-web
50          port: 80

host增加foo.bar.cn 同上面一样,就可以访问nginx页面。

traefik开启https支持、中间件使用

这里已经添加好args,ports https://github.com/cr-mao/develop/tree/main/k8s/k8s_use/discovery/traefik-advanced

这个是demo https://github.com/cr-mao/develop/tree/main/k8s/k8s_use/discovery/traefik_nginx_test

args添加参数

1- --entrypoints.http.address=:80
2- --entrypoints.https.address=:443

ports新增端口映射:

1- name: https
2  containerPort: 443
3  hostPort: 443

生成证书

1openssl req -newkey rsa:2048 -nodes -keyout tls.key -x509 -days 3650 -out tls.crt

创建Secret

1kubectl create secret generic test-nginx-cert --from-file=tls.crt --from-file=tls.key -n test

IngressRoute指定secret

1tls:
2  secretName: test-nginx-cert
1cd https://github.com/cr-mao/develop/tree/main/k8s/k8s_use/discovery/traefik_nginx_test
2
3kubectl apply -f .

https://web.foo.com/

工作负载

Deployment

可以扩容 缩容, 保证启动多少个pod 。

 1# 管理一组Pod
 2# replicas 2 -> node01(Pod x 1) node02(Pod x 1)
 3# node02(down)
 4# wait 30s -> node01(Pod x 2)
 5apiVersion: apps/v1
 6kind: Deployment
 7metadata:
 8  name: nginx-deployment
 9  namespace: test
10  labels:
11    app: nginx-deployment
12spec:
13  replicas: 2
14  selector:
15    matchLabels:
16      app: nginx-deployment-tp
17  template:
18    metadata:
19      labels:
20        app: nginx-deployment-tp
21    spec:
22      containers:
23        - name: nginx
24          image: nginx
25          imagePullPolicy: IfNotPresent
26      tolerations:
27        - key: "node.kubernetes.io/unreachable"
28          operator: "Exists"
29          effect: "NoExecute"
30          tolerationSeconds: 30

StatefulSet

管理有状态的应用

只使用 Deployment,多个实例之间是无关的,启动的顺序不固定,Pod 的名字、IP 地址、域名也都是完全随机的,这正是“无状态应用”的特点。 但对于“有状态应用”,多个实例之间可能存在依赖关系,比如 master/slave、active/passive,需要依次启动才能保证应用正常运行,外界的客户端也可能要使用固定的网络标识来访问实例,而且这些信息还必须要保证在 Pod 重启后不变。 还有绑定的存储卷。

下面 storageClassName: nfs-client, StorageClass 绑定一个 Provisioner 对象,之前安装了NFS Provisoner

 1apiVersion: v1
 2kind: Service
 3metadata:
 4  name: nginx-statefulset-svc
 5  namespace: test
 6spec:
 7  # ClusterIP | LoadBalancer |
 8  type: NodePort
 9  # headless service
10  # clusterIP: None
11  selector:
12    app: nginx-statefulset-tp
13  ports:
14    - name: http
15      port: 80
16      targetPort: 80
17      nodePort: 30085
18---
19# 管理一组Pod
20# replicas 2
21# 有序性 pod-0 pod-1(pod-0启动之后) -> 停止 pod-0停止(pod-1停止之后)
22# 有状态 id不变 - pvc(绑定pod) -> volumeClaimTemplate
23# 稳定服务发现 service->找到自己想找到的pod
24# curl pod名称.svc名称.命名空间.svc.cluster.local
25apiVersion: apps/v1
26kind: StatefulSet
27metadata:
28  name: nginx-statefulset
29  namespace: test
30  labels:
31    app: nginx-statefulset
32spec:
33  replicas: 2
34  serviceName: nginx-statefulset-svc
35  selector:
36    matchLabels:
37      app: nginx-statefulset-tp
38  template:
39    metadata:
40      labels:
41        app: nginx-statefulset-tp
42    spec:
43      containers:
44        - name: nginx
45          image: nginx
46          imagePullPolicy: IfNotPresent
47          volumeMounts:
48            - name: www
49              mountPath: /usr/share/nginx/html
50      tolerations:
51        - key: "node.kubernetes.io/unreachable"
52          operator: "Exists"
53          effect: "NoExecute"
54          tolerationSeconds: 30
55  volumeClaimTemplates:
56    - metadata:
57        name: www
58      spec:
59        resources:
60          requests:
61            storage: 100Mi
62        accessModes:
63          - ReadWriteOnce
64        storageClassName: nfs-client

pod 名有固定格式的, 集群间pod 可以有固定的服务发现方式进行通信。

 1root@k8smaster:/home/www/develop_study/k8s/k8s_install# kubectl get svc -n test
 2NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
 3nginx-statefulset-svc   ClusterIP   None            <none>        80/TCP         9h
 4
 5
 6
 7root@k8smaster:/home/www/develop_study/k8s/k8s_install# kubectl get pod -n test
 8NAME                                READY   STATUS    RESTARTS     AGE
 9nginx-statefulset-0                 1/1     Running   0            9h
10nginx-statefulset-1                 1/1     Running   0            9h
11
12
13
14root@k8smaster:/home/www/develop_study/k8s/k8s_install# kubectl exec -it nginx-statefulset-0 -n test -- sh
15# cat /etc/hosts
16# Kubernetes-managed hosts file.
17127.0.0.1	localhost
18::1	localhost ip6-localhost ip6-loopback
19fe00::0	ip6-localnet
20fe00::0	ip6-mcastprefix
21fe00::1	ip6-allnodes
22fe00::2	ip6-allrouters
2310.10.249.1	nginx-statefulset-0.nginx-statefulset-svc.test.svc.cluster.localnginx-statefulset-0
24# curl nginx-statefulset-0.nginx-statefulset-svc.test.svc.cluster.local
251111
26# curl nginx-statefulset-0
271111
28# curl nginx-statefulset-1.nginx-statefulset-svc.test.svc.cluster.local
292222

DaemonSet

看门狗,每个节点都会运行, master节点默认不会, 可以搞容忍污点 。 pod删除后,该节点还是再起来。

如kubeproxy(网络转发) 就是一个 DaemonSet, 如监控,日志收集 都适合用 DaemonSet

 1
 2# 管理一组Pod
 3# 每个node上部署一个pod(前提是:不干扰daemonSet调度)
 4# node上部署的pod不会被驱逐
 5apiVersion: apps/v1
 6kind: DaemonSet
 7metadata:
 8  name: nginx-daemonset
 9  namespace: test
10  labels:
11    app: nginx-daemonset
12spec:
13#  replicas: 2
14  selector:
15    matchLabels:
16      app: nginx-daemonset-tp
17  template:
18    metadata:
19      labels:
20        app: nginx-daemonset-tp
21    spec:
22      containers:
23        - name: nginx
24          image: nginx
25          imagePullPolicy: IfNotPresent

job

 1# 执行一次就结束的Pod
 2apiVersion: batch/v1
 3kind: Job
 4metadata:
 5  name: hello
 6  namespace: test
 7spec:
 8  # 尝试backoffLimit+1次 没有成功 则退出Job
 9  backoffLimit: 2
10  completions: 3
11  template:
12    spec:
13      # 仅支持 OnFailure Never
14      restartPolicy: Never
15      containers:
16        - name: busybox
17          image: busybox
18          imagePullPolicy: IfNotPresent
19          command:
20            - /bin/sh
21            - -c
22            - echo "Hello Job"

helm

概念

helm是 k8s的包管理器 , helm就是来解决资源整合的问题

好比Linux里面的yum、apt等

helm 拥有一个命令行工具,用于本地开发及管理chart

1、chart :Helm的打包格式叫做chart, 就是一系列文件, 它描述了一组相关的 k8s 集群资源

2、Repoistory :Helm chart 的仓库,Helm 客户端获取存储库中 chart 的索引文件和压缩包

安装

https://github.com/helm/helm

1wget https://get.helm.sh/helm-v3.10.3-linux-amd64.tar.gz
2tar zxvf helm-v3.10.3-linux-amd64.tar.gz
3mv xx/helm /usr/local/bin/helm

仓库

微软的chart仓库 http://mirror.azure.cn/kubernetes/charts/

很流行的 各种charts查询 Kubeapps Hub https://hub.kubeapps.com/charts/incubator

添加仓库

1helm repo add stable http://mirror.azure.cn/kubernetes/charts/
2
3helm repo update

搜索

1
2helm search repo stable/mysql
3
4# xxx 自己取的名字
5helm install xxx  stable/mysql

创建

可以看到一堆文件

1helm create mygin 

渲染

1helm install my  mygin --dry-run --debug 

渲染+安装

1helm install my  mygin -n myweb
2(helm install [NAME] [CHART] [flags])
1helm list 
2helm list -n myweb (命名空间)
3helm uninstall xxx 

模板语法简学

values

转义

1container:
2   command: "[\"/app/myserver\"]"

deployment.yaml

with 语法, 前面的-去掉空行

1  workingDir: /app
2  {{- with .Values.container.command }}
3  command: {{  . }}
4  {{- end }}

toYaml 使用yaml格式填充 、 nindent 换行加缩进

1container:
2  command: "[\"/app/gosky\",\"serve\",\"--env=local\"]"
3  volumeMounts:
4    - name: v1
5      mountPath: /app
 1      containers:
 2        - name: {{ .Chart.Name }}
 3          securityContext:
 4            {{- toYaml .Values.securityContext | nindent 12 }}
 5          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
 6          imagePullPolicy: {{ .Values.image.pullPolicy }}
 7          workingDir: /app
 8          {{- with .Values.container.command }}
 9          command: {{  . }}
10          {{- end }}
11          ports:
12            - name: http
13              containerPort: 7001
14              protocol: TCP
15          volumeMounts: {{ toYaml .Values.container.volumeMounts | nindent 12 }}
16          resources:
17            {{- toYaml .Values.resources | nindent 12 }}

私有镜像

云效 https://repomanage.rdc.aliyun.com/my/helm-repos/namespaces

打包

1helm package mygin 

helm push mygin-0.1.0.tgz $NAMESPACE

helm fetch xxx/xxxx 下载chart到本地

提交完成后 刷新repo

helm repo update

helm search repo $NAMESPACE/mygin

安装试一试 helm install xxx $NAMESPACE/mygin -n myweb

更新 help upgrate xxx mygin -n myweb

helm 安装nginx-ingress

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

没科学上网参考下面

 1
 2helm install my-nginx ingress-nginx/ingress-nginx 
 3
 4不出意外会爆一个错
 5k8s.gcr.io/ingress-nginx/controller:v0.40.2 @sha256:46ba23c3fbaafd9e5bd01ea85b2f921d9f2217be082580edc22e6c704a83f02f 
 6
 7
 8要么科学上网,要么找个一样的镜像。
 9
10docker pull giantswarm/ingress-nginx-controller:v0.40.2
11
12然后改tag
13
14docker tag giantswarm/ingress-nginx-controller:v0.40.2   k8s.gcr.io/ingress-nginx/controller:v0.40.2
15
16删之前的tag
17
18docker rmi giantswarm/ingress-nginx-controller:v0.40.2

下载chart到本地

1helm fetch ingress-nginx/ingress-nginx
2tar zxvf ingress-nginx-4.4.0.tgz

修改部分内容后再次安装 values.yaml

https://github.com/cr-mao/develop/blob/main/k8s/helm/ingress-nginx/values.yaml

 1    controller.kind=DaemonSet
 2   #  把这个值设置为true:
 3   # pod中服务可以使用宿主机的网络接口,宿主主机所在的局域网上所有网络接口都可以访问到该应用程序
 4
 5   controller.hostNetwork=true  
 6
 7
 8  ## Use host ports 80 and 443
 9  ## Disabled by default
10  hostPort:
11    # -- Enable 'hostPort' or not
12    enabled: true
13    
14    
15    #    type: LoadBalancer
16    type: NodePort
17
18    ## type: NodePort
19    ## nodePorts:
20    ##   http: 32080
21    ##   https: 32443
22    ##   tcp:
23    ##     8080: 32808
24    nodePorts:
25      http: "32080"
26      https: "32808"
27      tcp: {}
28      udp: {}
29      
30      
31     admissionWebhooks:
32    annotations: {}
33    # ignore-check.kube-linter.io/no-read-only-rootfs: "This deployment needs write access to root filesystem".
34
35    ## Additional annotations to the admission webhooks.
36    ## These annotations will be added to the ValidatingWebhookConfiguration and
37    ## the Jobs Spec of the admission webhooks.
38    enabled: false

helm install my-nginx ingress-nginx -n my-nginx-ingress

更新命令

helm upgrade my-nginx ingress-nginx -n my-nginx-ingress

安装完只有ingress classes

部署负载均衡 ,service 之前就已经有搞过, ingressClassName 填nginx即可。

ingress.yaml

 1apiVersion: networking.k8s.io/v1
 2kind: Ingress
 3metadata:
 4  name: ngx-ing
 5
 6  # customize the behaviors of nginx
 7  annotations:
 8    nginx.org/lb-method: round_robin
 9
10spec:
11  ingressClassName: nginx
12
13  rules:
14    - host: ngx.test
15      http:
16        paths:
17          - path: /
18            pathType: Prefix
19            backend:
20              service:
21                name: ngx-svc
22                port:
23                  number: 80
1curl ngx.test # 看效果即可

k8s认证和授权

用户账号: 集群外部访问时使用的用户,如kubectl 访问集群资源用的 kubernetes-admin (~/.kube/config里),k8s本身不记录这些账号.

创建客户端证书

默认认证方式:客户端证书

1mkdir ua
2cd ua
3# 生成客户端私钥
4openssl genrsa -out client.key 2048
5
6#根据私钥生成csr ,/CN制定用户名为crmao
7openssl req -new -key client.key -out client.csr -subj "/CN=crmao"
8# 根据k8s的CA证书生成我们用户的客户端证书
9sudo openssl x509 -req -in client.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out client.crt -days 365

使用证书请求api、设置上下文

其中 可以用 –insecure 代替 –cacert /etc/kubernetes/pki/ca.crt 从而忽略服务端证书验证

 1vagrant@k8smaster:~/ua$ curl --cert ./client.crt --key ./client.key --cacert /etc/kubernetes/pki/ca.crt -s https://192.168.56.80:6443/api
 2{
 3  "kind": "APIVersions",
 4  "versions": [
 5    "v1"
 6  ],
 7  "serverAddressByClientCIDRs": [
 8    {
 9      "clientCIDR": "0.0.0.0/0",
10      "serverAddress": "192.168.56.80:6443"
11    }
12  ]
13}

如果你忘了证书设置的CN(Common name)是啥 可以用下面的命令搞定

1openssl x509 -noout -subject -in client.crt

设置用户到~/.kube/config

1 kubectl config --kubeconfig=/home/vagrant/.kube/config set-credentials crmao --client-certificate=/home/vagrant/ua/client.crt --client-key=/home/vagrant/ua/client.key

创建上下文

1kubectl config --kubeconfig=/home/vagrant/.kube/config set-context user_context --cluster=kubernetes  --user=crmao

查看上下文

1vagrant@k8smaster:~/ua$ kubectl config get-contexts
2CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
3*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin
4          user_context                  kubernetes   crmao

指定当前上下文

1kubectl config --kubeconfig=/home/vagrant/.kube/config use-context user_context
2
3#  kubectl config get-contexts

Role,Rolebinding

它可以包含一堆权限。用于授予对单个命名空间的资源访问

查看角色

1kubectl get role --all-namespaces

创建角色

1kind: Role
2apiVersion: rbac.authorization.k8s.io/v1
3metadata:
4  namespace: default
5  name: mypod
6rules:
7  - apiGroups: ["*"]
8    resources: ["pods"]
9    verbs: ["get", "watch", "list"]

创建角色绑定

1kubectl create rolebinding mypodbinding  -n default  --role mypod --user crmao

or

 1apiVersion: rbac.authorization.k8s.io/v1
 2kind: RoleBinding
 3metadata:
 4  creationTimestamp: null
 5  name: mypodrolebinding
 6roleRef:
 7  apiGroup: rbac.authorization.k8s.io
 8  kind: Role
 9  name: mypod
10subjects:
11- apiGroup: rbac.authorization.k8s.io
12  kind: User
13  name: crmao

切成普通用户,查看是否有权限访问pod 权限

1kubectl config use-context user_context # user_context 上面创建的crmao这个用户的上下文。
2kubectl get pod 

clusterRole,RoleBinding,ClusterRoleBinding

管理集群中多个 namespace,就需要使用到clusterrole

绑定既可以使用RoleBinding,也可以使用ClusterRoleBinding ( 两者效果不同)

 1apiVersion: rbac.authorization.k8s.io/v1
 2kind: ClusterRole
 3metadata:
 4  name: mypod-cluster
 5rules:
 6  - apiGroups: [ "*" ]
 7    resources: [ "pods" ]
 8    verbs: [ "get", "watch", "list" ]
 9---
10apiVersion: rbac.authorization.k8s.io/v1
11kind: RoleBinding
12metadata:
13  name: mypodrolebinding-cluster
14  # 指定命名空间
15  namespace: kube-system
16roleRef:
17  apiGroup: rbac.authorization.k8s.io
18  kind: ClusterRole
19  name: mypod-cluster
20subjects:
21  - apiGroup: rbac.authorization.k8s.io
22    kind: User
23    name: crmao

那么这个crmao用户就可以看 kube-system命名空间下的 pod 情况了。

配置使用token的方式请求api

head -c 16 /dev/urandom | od -An -t x | tr -d ’ ’ (’ ‘之间有个空格) kubectl config set-credentials crmao –token=4e2f6f4250a43ce94426b6264dad2609

sudo vi /etc/kubernetes/pki/token_auth 塞入如下内容 4e2f6f4250a43ce94426b6264dad2609,crmao,1001

然后是修改api-server启动参数

sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml

加入 –token-auth-file=/etc/kubernetes/pki/token_auth

1 curl -H "Authorization: Bearer 4e2f6f4250a43ce94426b6264dad2609" https://192.168.56.80:6443/api/v1/namespaces/default/pods --insecure

创建账号ServiceAccount

查看 是这样的:

kubectl get sa -n xxxx (不写-n 就是默认default)

用命令创建一个

1kubectl  create  serviceaccount   mysa

每个namespace都会有一个默认的 default账号,且sa局限在自己所属的namespace中。而UserAccount是可以跨ns的

 1vagrant@k8smaster:/etc/kubernetes/pki$ kubectl config get-contexts
 2CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
 3          kubernetes-admin@kubernetes   kubernetes   kubernetes-admin
 4*         user_context                  kubernetes   crmao
 5vagrant@k8smaster:/etc/kubernetes/pki$ kubectl config use-context kubernetes-admin@kubernetes
 6Switched to context "kubernetes-admin@kubernetes".
 7vagrant@k8smaster:/etc/kubernetes/pki$ kubectl config get-contexts
 8CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
 9*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin
10          user_context                  kubernetes   crmao
11vagrant@k8smaster:/etc/kubernetes/pki$ kubectl get sa
12NAME      SECRETS   AGE
13default   1         121d
 1kubectl  create  serviceaccount   mysa
 2
 3vagrant@k8smaster:/etc/kubernetes/pki$ kubectl get sa
 4NAME      SECRETS   AGE
 5default   1         121d
 6mysa      1         7s
 7
 8
 9vagrant@k8smaster:/etc/kubernetes/pki$  kubectl describe sa mysa
10Name:                mysa
11Namespace:           default
12Labels:              <none>
13Annotations:         <none>
14Image pull secrets:  <none>
15Mountable secrets:   mysa-token-22j97 (看这个)
16Tokens:              mysa-token-22j97
17Events:              <none>
18
19
20
21
22kubectl describe secrets mysa-token-22j97 

第二种方式创建,用yaml 。

kubectl create serviceaccount mysa -o yaml –dry-run=client

进阶一下,可以这样

kubectl create serviceaccount mysa -o yaml –dry-run=client > mysa.yaml

ServiceAccount赋予权限、外部访问API

账户绑定集群角色

上面创建一个 clusterrole叫做 mypod-cluster 此权限 可以查看 pods列表

安装 解析json的工具

sudo apt install jq

1kubectl create clusterrolebinding mysa-crb --clusterrole=mypod-cluster --serviceaccount=default:mysa
2
3kubectl get sa  mysa
4kubectl get sa  mysa -o json
5kubectl get sa  mysa -o json | jq  '.secrets[0].name'
6kubectl get sa  mysa -o json | jq -Mr '.secrets[0].name'

k8s的token是base64后的, 要反检一下。

 1vagrant@k8smaster:/etc/kubernetes/pki$ kubectl get sa  mysa -o json | jq -Mr '.secrets[0].name'
 2mysa-token-22j97
 3
 4
 5vagrant@k8smaster:/etc/kubernetes/pki$ kubectl get secret  $(kubectl get sa  mysa -o json | jq -Mr '.secrets[0].name'
 6) -o json | jq -Mr '.data.token' | base64 -d
 7
 8
 9mysatoken=$(kubectl get secret  $(kubectl get sa  mysa -o json | jq -Mr '.secrets[0].name') -o json | jq -Mr '.data.token' | base64 -d)
10
11
12vagrant@k8smaster:/etc/kubernetes/pki$ kubectl get endpoints
13NAME         ENDPOINTS                         AGE
14kubernetes   192.168.56.80:6443                121d
15ngx-svc      10.10.249.29:80,10.10.249.43:80   88d
16
17vagrant@k8smaster:/etc/kubernetes/pki$ curl -H "Authorization: Bearer $mysatoken" --insecure  https://192.168.56.80:6443/api/v1/namespaces/default/pods

SerciveAccount 在POD里访问k8s API(token的方式)

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: myngxdepoly
 5spec:
 6  selector:
 7    matchLabels:
 8      app: nginx
 9  replicas: 1
10  template:
11    metadata:
12      labels:
13        app: nginx
14    spec:
15      #  加入这个 ,指定账号
16      serviceAccountName: mysa
17      containers:
18        - name: nginxtest
19          image: nginx:alpine
20          imagePullPolicy: IfNotPresent
21          ports:
22            - containerPort: 80
 1# 进入pod
 2kubectl exec -it  myngxdepoly-58bddf9b8d-qmdq7 -- sh
 3
 4TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`
 5APISERVER="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT"
 6
 7 curl --header "Authorization: Bearer $TOKEN" --insecure -s $APISERVER/api
 8
 9# 我们可以看到 上面是可以的,但下面不可以,因为default账号没有列出pods的权限 ,当上面当yaml 加入了   serviceAccountName: mysa,就可以看pod 列表权限了。
10curl --header "Authorization: Bearer $TOKEN" --insecure -s $APISERVER/api/v1/namespaces/default/pods 

serviceAccount 在pod里访问k8s api(证书方式)

更常用的方式是直接用证书 ,上面是用–insecure 跳过了证书

证书的位置在:

/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

1#进入pod 执行
2TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`
3APISERVER="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT"
4curl --header "Authorization: Bearer $TOKEN" --cacert  /var/run/secrets/kubernetes.io/serviceaccount/ca.crt   $APISERVER/api/v1/namespaces/default/pods