每天5分钟玩转K8S (看书笔记)

文章目录

  • 第3章 部署k8s集群
    • 安装docker
    • 安装kubeadm,kubelet,kubectl
    • 使用kubeadm创建集群
      • 1.kubeadm初始化创建master
      • 2.配置kubectl
      • 3.安装pod网络
      • 4.添加node节点
      • 总结
  • 第5章 运行应用
    • Deployment
    • DaemonSet
    • Job
  • 第6章 通过service访问pod
    • 创建service
    • 通过dns访问Service
    • 访问service
  • 第八章 health check
    • 默认检测
    • liveness探测
    • readiness探测
    • 三者的区别
    • health check在扩容和更新中的作用
  • 第九章 数据管理
    • Volume
      • emptyDir
      • hostPath
      • 外部Storage Provider
    • Pv和Pvc
      • 回收pv
      • Pv动态供给
      • 实例
  • 第10章 Secret和Configmap
    • Secret
      • 创建Secret
      • 在pod中使用Secret
    • ConfigMap
      • 创建ConfigMap
      • 使用ConfigMap
  • 第11章 Helm K8s的包管理器
    • 安装Helm3
    • Helm3常用指令
    • 创建Chart
      • Chart.yaml
      • values.yaml
    • 搭建本地repo
      • 使用chartmuseum镜像搭建repo仓库
  • 第12章 网络
    • k8s网络模型
      • 1. pod内容器之间通信
      • 2. pod之间通信
      • 3. pod和service之间通信
      • 4. 外部访问
    • 各种网络方案

第3章 部署k8s集群

安装docker

安装kubeadm,kubelet,kubectl

使用kubeadm创建集群

1.kubeadm初始化创建master

kubeadm init --apiserver-advertise-address 192.168.56.105 --pod-network-cidr=10.244.0.0/16

–apiserver-advertise-address 指明了使用master与其他节点的通信ip

–pod-network-cidr 指定pod网络的范围。

2.配置kubectl

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

kubectl 需要通过这个config文件访问K8s的apiserver,来获取集群的信息。

KUBECONFIG=xxx.conf kubectl get pods

所以使用不同的配置文件,就可以访问不同的集群

3.安装pod网络

没有pod网络,集群中的pod就不能相互通信。K8s有多种网络

flannel
创建flannel网络

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

Cannal

4.添加node节点

在node节点上执行

kubeadm join --token xxxx 192.168.56.105:6443

token是master节点 kubeadm init时创建。可以通过kubeadm token list获取。

总结

k8s的组件都是由kubeadm控制,从官方库下载的镜像,然后运行的容器。他们都是k8s中的pod,属于集群中的一部分。

kubelet是唯一没有以容器形式运行的k8s组件。以systemd服务运行。

第5章 运行应用

Deployment

k8s支持两种创建资源的方式

  1. 使用命令创建
kubectl run nginx-deployment --image=nginx:1.9.1 --replicas2
  1. 使用配置文件
apiVersion: apps/v1         #apiserver版本,每个版本内功能可能不相同
kind: Deployment            #资源类型
metadata:                   #deployment元数据,name是必要元数据项
  name: bxy-local-nginx
  namespace: kube-system    #命名空间
spec:                       #deployment资源清单
  replicas: 1               #副本数量
  selector:                 #(必须项)保证和pod标签一致即可
    matchLabels:
      k8s-app: bxy-local-nginx-label
  template:                 #pod模板
    metadata:               #pod元数据,至少有一个label
      labels:               #pod标签(必需项)
        k8s-app: bxy-local-nginx-label
    spec:                   #pod规格
      imagePullSecrets:
      - name: regcred
      containers:           #容器描述,name和image是必须
      - name: bxy-local-nginx
        image: mirrors.tencent.com/tcnp_tkestack/busybox:latest
        imagePullPolicy: IfNotPresent  #如果本地没有则拉取镜像库
        volumeMounts:       #挂载卷配置
        - mountPath: /echo_dir      #挂载容器目录
          name: bxy-local-pv-volume     #绑定的pv名称,和volumes.name一致
        args:
        - /bin/sh
        - -c
        - echo "hello world" > /echo_dir/hello; sleep 3000
      volumes:              #pv描述
      - name: bxy-local-pv-volume      #pv名称 
        persistentVolumeClaim:
          claimName: bxy-local-pvc-volume   #绑定的pvc名称
kubectl apply -f nginx.yml      应用nginx.yml配置文件
kubectl delete -f nginx.yml  或者 kubectl delete deployment_name 删除deployment

kubectl describe pod -n namespace 查看pod的详细情况

  1. 将master变成node使用。
kubectl tain node k8s-master node-role.kubernetes.io/master-    将master配置成node

kubectl tain node k8s-master node-role.kubernetes.io/master="":NoSchedule   恢复master only
  1. 使用label控制pod位置
  • 通过label将pod部署到指定node
    • 1.给node添加标签
    kubectl label node k8s-node1 disktype=ssd       添加标签
    kubectl label node k8s-node1 disktype-          删除标签
    
    • 2.修改deployment配置
    spec:
        containers:
        - name:nginx
          image: nginx:1.0.9
        nodeSelector:
          disktype: ssd
    
  • 直接指定部署的node
    spec:
        nodename: k8s-node1

nodename就是主机名,修改主机名

kubectl --hostname-override=node1

DaemonSet

DaemonSet的不同之处,每个node只能运行一个副本,一般用于监控daemon,日志收集daemon,存储daemon.

Job

容器分为服务型和工作型,服务型需要一直运行,工作型一次性任务,完成后容器退出。

第6章 通过service访问pod

pod内的容器共享同一个ip和端口空间,他们之间可以使用localhost通信。类似于同一个机器上的不同进程。

每一个pod都会分配一个IP,这个ip只能被集群内的容器和节点访问。
Pod可能会频繁地销毁和创建,也就是说Pod的IP不是固定的。为了解决这个问题,Service提供了访问Pod的抽象层。无论后端的Pod如何变化,Service都作为稳定的前端对外提供服务。同时,Service还提供了高可用和负载均衡功能,Service负责将请求转发给正确的Pod。

创建service

apiVersion: apps/v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx-test  #pod标签
  ports:
  - protocol: TCP
    port: 8080      #将service端口映射到pod的80端口
    targetPort: 80
    nodePort: 30326     #将service的8080端口绑定到宿主机的30326端口,这样外网机器就能通过宿主机的30326访问pod

转发pod ip: 集群中的pod通过ip相互访问。现假设pod1通过pod2的ip1来访问服务,现在Pod2重启,分配了一个新的ip2。于是为了访问pod2,就需要修改pod1的访问配置,这显然是不合理的。service可以映射一组pod,k8s会维护service和pod的映射关系。无论pod如何变化,service的ip都不会变,所以客户端只需要通过service就能访问到pod。

通过dns访问Service

集群中的pod除了通过service的ip访问之外,还可以使用dns访问。

kubeadm部署kube-dns组件,每当有新的service创建,就会在dns组件中添加service - dns记录。集群中的pod通过.就能访问service。

访问service

k8s提供了多种访问service的方法

  • ClusterIP: service通过集群内部的ip对外提供服务,只有集群内的容器和节点可以访问。(内部访问)
  • NodePort: 在主机上绑定一个代理端口,通过主机网络访问集群service和pod。 (外部访问)
  • LoadBalanceer:通过云服务商提供的load balance对外提供服务。cloud provider负责将流量导向service。该方法主要是部署在云上使用。例如腾讯云,阿里云等。 (外部访问)

第八章 health check

k8s提供了健康检测主要有三种

默认检测

只要容器启动指令返回值不为0就重启

apiVersion: apps/v1
kind: pod
metadata:
  labels:
    test: healthcheck
    name: healthcheck
spec:
  restartPlicy: OnFailure
  containers:
  - name: healthcheck
    image: busybox
    args:
    - /bin/bash
    - -c
    - sleep 1; exit 1

liveness探测

探测指令执行失败,返回非零,重启容器

spec:
  restartPlicy: OnFailure
  containers:
  - name: healthcheck
    image: busybox
    args:
    - /bin/bash
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
        initialDelaySeconds: 10     #10s后开始探测
        periodSeconds: 5        #探测间隔5s

readiness探测

探测指令执行失败,返回非零,把pod从service负载均衡中剔除。

spec:
  restartPlicy: OnFailure
  containers:
  - name: healthcheck
    image: busybox
    args:
    - /bin/bash
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    redinessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
        initialDelaySeconds: 10     #10s后开始探测
        periodSeconds: 5        #探测间隔5s

三者的区别

  1. 默认探测是保证容器成功启动。如果容器启动失败,就会重启。
  2. liveness探测的情况,用于容器启动成功,但是有故障,无法正常提供服务。通过探测发现故障容器,并重启。
  3. readiness探测的情况是,容器启动成功,当前可能还没有做好准备(或者故障),则该pod不会被加入到service负载均衡中。
  4. 1关注的是容器启动指令,2,3关注的是探测指令。

health check在扩容和更新中的作用

spec:
  containers:
  - name: web
    image: myhttpd
    ports:
    - containerPort: 8080
    readlinessProbe:
      httpGet:
        scheme: HTTP
        path: /healthy
        port: 8080
     initialDelaySeconds: 10
     periodSeconds: 5

httpGet探测判断成功的条件是http请求返回的代码在200~400之间。
在扩容和更新的过程中,新的pod启动需要一段时间准备,通过探测可以知道当前pod服务是否准备好了,如果服务准备好了,就可以加入到负载均衡中。

第九章 数据管理

Volume

emptyDir

emptyDir volume 生命周期和pod一致
pod的所有容器都共享volume,他们可以指定各自的mount路径。

spec:
 containers:
  - name: producer
    image: busybox
    volumeMouts:        #挂载volume
    - mountPath: /producer_dir
      name: shared-volume
    args:
    - /bin/bash
    - -c
    - echo "hello world" > /producer_dir/hello; sleep 3000

  - name: consumer
    image: busybox
    - mountPath: /consumer_dir
      name: shared-volume
    args:
    - /bin/bash
    - -c
    - cat /consumer_dir/hello; sleep 3000
 volumes:           #创建volume
 - name: shared-volume
 emptyDir: {}

hostPath

把node宿主机上的目录挂载给容器。一般不会用这种,增加了pod和节点的耦合。

    volumeMouts:        #挂载volume
    - mountPath: /producer_dir
      name: k8s
      
    volumes:    
    - name: k8s
      hostPath:
        path: /etc/k8s      #宿主机目录

外部Storage Provider

如果k8s部署在公有云上,可以直接使用云硬盘作为volume

Pv和Pvc

在实际生产中,12两种方案都不适用。使用3方案,在编写yml的时候,必须知道volume的信息。而pod通常由开发人员维护,而volume通常由存储系统的管理人员负责。也就是说开发人员要总是去问管理人员新的volume信息。这显然是不合理的,于是k8s给出了pv和pvc的解决方案。

  • pv(PersistentVolume)是外部存储系统中的一块存储空间。由管理源创建和维护,生命周期独立于pod。
  • pvc(PersistentVolumeClaim) 是对pv的申请。由普通用户创建和维护。

管理人员提前创建pv,然后开发人员创建pvc指明存储资源的容量大小和访问模式等信息。K8s就会查找并提供满足条件的pv。

PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv1
  labels:
    name: nfs
spec:
  capacity:
    storage: 1Gi        #PV容量
  accessModes: 
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs-name
  nfs:
    path: /nfsdata/pv1
    server: 192.168.56.105

  **** 本地文件作为存储资源
  volumeMode: Filesystem
  storageClassName: local-name
  local:
    path: /data/home/waynebfhu/k8s/pv1
  • accessModes指定访问模式为ReadWriteOnce,支持的访问模式有3种:ReadWriteOnce表示PV能以read-write模式mount到单个节点,ReadOnlyMany表示PV能以read-only模式mount到多个节点,ReadWriteMany表示PV能以read-write模式mount到多个节点
  • storageClassName指定PV的class为nfs。相当于为PV设置了一个分类,PVC可以指定class申请相应class的PV。

PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc1
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs
  selector:
    matchLabels:
      name: nfs

pvc创建成功后,pv就和pvc绑定在一起了。之后就是在pod中使用存储了

Pod.yml

spec:
   containers:
     volumeMounts:
     - mountPath: "/mydata"
       name: mydata

  volumes:
  - name: mydata
    persistentVolumeClaim:
      claimName: mypvc1

回收pv

删除pvc,pv就会被回收。

persistentVolumeReclaimPolicy: Recycle pv回收后,数据被删除。 Retain 则数据保留。

Pv动态供给

动态供给是指StorageClass动态创建Pv

apiVersion: storage.k8s.io/v1                                                                        
kind: StorageClass                                                                          
metadata:                                                                                            
  name: standard                                                                          
provisioner: kubernetes.io/no-provisioner                                                            
parameters:
  type: gp2
reclaimPolicy: Retain  
apiVersion: storage.k8s.io/v1                                                                        
kind: StorageClass                                                                          
metadata:                                                                                            
  name: slow                                                                          
provisioner: kubernetes.io/no-provisioner                                                            
parameters:
  type: io1
  zones: us-east-1d
  iopsPerGB: "10"
reclaimPolicy: Retain  

provisioner 指定了生成aws ebs
pvc和pv中的storageClassName 就是指的上述metada中的name,也就是standard和slow

实例

mysql数据库,可以把数据库数据存放到pv中。当pod1故障后,切换新的pod,重新读取pv中的数据。

第10章 Secret和Configmap

在实际生产中,我们应该实现配置文件和容器分离。
例如密码,token等敏感信息,可以使用Secret。其他的不敏感信息,可以使用Configmap保存。

Secret

创建Secret

(1)通过–from-env-file

cat << EOF > secret.txt
username=admin
password=123456
EOF
kubectl create secret generic mysecret --from-env-file=secret.txt

文件中的每行key-value对应一个信息条目
(2)通过YAML配置文件

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
data:
  username: YWRtaW4=
  password: MTIzNDU2

文件中的敏感数据必须通过base64编码后的结果。

echo -n admin | base64      
echo -n YWRtaW4=| base64 --decode  反编码
kubectl edit secret mysecret 查看mysecret

在pod中使用Secret

(1)volume形式

spec:
  volumeMounts:
  - name: foo
    mountPath: "/etc/foo"
    readOnly: true
volumes:
- name: foo
  secret: 
    secretName: mysecret

在pod的/etc/foo目录下会根据key分别生成名为username和password的两个文件,文件内容就是之前设置的value。

也可以自定义文件名

volumes:
- name: foo
  secret:
    secretName: mysecret
    items:
    - key: username
      path: my-username
    -key: password
      path: my-password

(2)环境变量形式

env:
  - name: SECRET_USERNAME      # 环境变量名
    valueFrom:
      secretKeyRef:
        name: mysecret
        key: username          # 变量值 
  - name: SECRET_PASSWORD
    valueFrom:
      secretKeyRef:
        name: mysecret
        key: password

ConfigMap

创建ConfigMap

(1)通过–from-env-file

cat << EOF > secret.txt
username=admin
password=123456
EOF
kubectl create secret generic myconfig --from-env-file=secret.txt

文件中的每行key-value对应一个信息条目
(2)通过YAML配置文件

apiVersion: v1
kind: Secret
metadata:
  name: myconfig
data:
  username: admin
  password: 123456

明文形式

使用ConfigMap

(1) Volume形式使用

spec:
  volumeMounts:
  - name: foo
    mountPath: "/etc/foo"
    readOnly: true
volumes:
- name: foo
  configMap:
    name: myconfig
    items:
      - key: logging.conf
        path: myapp/logging.conf

文件会被创建在pod的/etc/foo/myapp/logging.conf
(2)环境变量形式

env:
  - name: CONF_USERNAME      # 环境变量名
    valueFrom:
      configMapKeyRef:
        name: myconfig
        key: username          # 变量值 
  - name: CONF_PASSWORD
    valueFrom:
      configMapKeyRef:
        name: myconfig
        key: password

第11章 Helm K8s的包管理器

k8s是用来管理容器的,通过K8S的文件控制容器的部署。
helm是用来管理k8s的容器部署文件的。就是说将所有的k8s容器部署文件打包给helm管理。

也就是说k8s用来管理容器
helm用来管理k8s的

安装Helm3

Helm3和Helm2的区别比较大,且不兼容。所以后续我们都使用Helm3

# 下载helm3,解压并拷贝到/usr/local/bin目录下
wget https://get.helm.sh/helm-v3.5.3-linux-amd64.tar.gz
tar -zxvf helm-v3.5..3-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm

或者

sudo curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

已经不再使用helm stable仓库了。而是迁移到artifact hub。artifact hub不是一个仓库,而是所有charts仓库的入口。

命令补全

# 在~/.bashrc 中加入
source <(helm completion bash)

Helm3常用指令

helm repo add bitnami https://charts.bitnami.com/bitnami        #添加repo库
helm search repo stable             #查找charts
helm install stable/mysql --generate-name  #通过helm安装release
helm uninstall stable/mysql         #卸载release
helm ls                             #查看用helm安装的release
helm show all stable/mysql          #查看详情
helm pull stable/mysql              #下载charts
helm search repo [reponame]         #查看库里面的镜像
helm create mychart                 #创建chart
helm package mychart                #打包chart包,生成tgz文件
helm push mychart/mychart.0.1.tgz localrepo  #上传chart包到repo仓库

创建Chart

创建一个Chart,分为两个步骤

  1. 创建docker镜像
  2. 创建chart
helm create chart.name    创建chart模板,修改该模板就能创建我们自己的chart

Chart.yaml

应用更新就是修改该文件

apiVersion: v2
name: hello-helm
description: A Helm chart for Kubernetes

# 分为application 和 library
type: application

# chart的版本号,每次修改了chart都要修改当前版本
version: 0.1.0 

# 容器tag
appVersion: "1.0.4"

values.yaml

用来描述chart配置的文件,会根据该配置生成对应的 k8s管理文件

replicaCount: 1

image:
  repository: dev.registry.works:30984/hello-hw     #镜像
  pullPolicy: IfNotPresent                          #拉取镜像的规则
  # Overrides the image tag whose default is the chart appVersion.
  tag: ""

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

podAnnotations: {}

podSecurityContext: {}
  # fsGroup: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: chart-example.local
      paths:
      - path: /
        backend:
          serviceName: chart-example.local
          servicePort: 80
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #   cpu: 100m
  #   memory: 128Mi
  # requests:
  #   cpu: 100m
  #   memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity: {}

搭建本地repo

Helm chart对仓库的要求并不高,需要你对外提供yaml文件和tar文件的web服务即可.

使用chartmuseum镜像搭建repo仓库

chartmuseum镜像给我们提供了repo仓库的功能。

mkdir /opt/charts  #创建repo库的文件存放目录

docker run -d \
  -p 4002:8080 \
  -e DEBUG=1 \
  -e STORAGE=local \
  -e STORAGE_LOCAL_ROOTDIR=/charts \
  -v /opt/charts:/charts \
  chartmuseum/chartmuseum:latest
  
curl localhost:4002/api/charts      
{}          测试repo是否搭建完成,如果能正确访问,搭建成功

helm repo add myrepo http://9.134.35.171:4002   #添加库

第12章 网络

k8s网络模型

Kubernetes采用的是基于扁平地址空间的网络模型,集群中的每个Pod都有自己的IP地址,Pod之间不需要配置NAT就能直接通信。另外,同一个Pod中的容器共享Pod的IP,能够通过localhost通信。应用可以非常方便地从传统网络迁移到Kubernetes。每个Pod可被看作是一个个独立的机器,而Pod中的容器则可被看作同一机器中的不同进程。

K8S的网络模型分为4个部分

1. pod内容器之间通信

pod内的容器共享同一个本地文件系统,IPC和网络空间。他们之间直接使用localhost:port通信

2. pod之间通信

pod之间通过集群给的ip通信

3. pod和service之间通信

在Kubernetes集群中,Pod可能会频繁地销毁和创建,也就是说Pod的IP不是固定的。为了解决这个问题,Service提供了访问Pod的抽象层。无论后端的Pod如何变化,Service都作为稳定的前端对外提供服务。同时,Service还提供了高可用和负载均衡功能,Service负责将请求转发给正确的Pod。

4. 外部访问

k8s提供了两种外界访问pod的方式:

  • NodePort Service通过绑定宿主机的端口,对外提供服务。
  • LoadBalancer Service利用cloud provider提供的load balancer对外提供服务,cloud provider负责将load balancer的流量导向Service。目前支持的cloudprovider有GCP、AWS、Azur等。

各种网络方案

为了保证网络方案的标准化、扩展性和灵活性,Kubernetes采用了ContainerNetworking Interface(CNI)规范。

目前已有多种支持Kubernetes的网络方案,比如Flannel、Calico、Canal、Weave Net等。因为它们都实现了CNI规范,用户无论选择哪种方案,得到的网络模型都一样。都必须实现网络模型的4种通信情况。

你可能感兴趣的:(每天5分钟玩转K8S (看书笔记))