清朝云资源网

博客

  • kubernetes 之 sealos 搭建高可用集群

    kubernetes 之 sealos 搭建高可用集群

    kubernetes 之 sealos 搭建高可用集群

    post-393-63074a9e4f28e

    如图所示,kuernetes组件组件主要可分为APISERVICE、replication CrontrollerManger、Scheduler、ETCD、Kubelet、Kube_proxy等。部署高可用,实际就是这些组件的高可用。
    由于ETCD使用raft算法,所以当部署多个master节点时,会自动组成高可用;CrontrollerManger与Scheduler在设计时也自动组成了高可用。所以搭建kubernetes的高可用就是搭建apiserver的高可用

    post-393-63074a9e9e7e7

    注意事项

    1. 必须同步所有服务器时间
    2. 所有服务器主机名不能重复
    3. 系统支持:centos7.6以上(其中centos8不支持) ubuntu16.04以上
    4. 内核推荐4.14以上, 系统推荐:centos7.7

    部署

    角色 ip 系统
    master01 192.168.234.136 CentOS Linux release 7.7.1908 (Core)
    master02 192.168.234.137 CentOS Linux release 7.7.1908 (Core)
    master03 192.168.234.138 CentOS Linux release 7.7.1908 (Core)
    node01 192.168.234.139 CentOS Linux release 7.7.1908 (Core)

    升级系统内核

    参考站内博客Linux系统内核升级

    设置时间同步

    yum -y install ntpdate && \
    systemctl start ntpdate && systemctl enable ntpdate && \
    ntpdate ntp.aliyun.com

    设置主机名并配置hosts配置文件

    192.168.234.136 master01
    192.168.234.137 master02
    192.168.234.138 master03
    192.168.234.139 node01

    关闭防火墙、selinux、以及swap分区

    systemctl stop firewalld && systemctl disable firewalld
    setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
    swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

    调整内核参数

    cat > /etc/sysctl.d/kubernetes.conf<<EOF
    net.bridge.bridge-nf-call-iptables=1
    net.bridge.bridge-nf-call-ip6tables=1
    net.ipv4.ip_forward=1
    net.ipv4.tcp_tw_recycle=0
    vm.swappiness=0
    vm.overcommit_memory=1
    vm.panic_on_oom=0
    fs.inotify.max_user_instances=8192
    fs.inotify.max_user_watches=1048576
    fs.file-max=52706963
    fs.nr_open=52706963
    net.ipv6.conf.all.disable_ipv6=1
    net.netfilter.nf_conntrack_max=2310720
    EOF
    
    sysctl -p /etc/sysctl.d/kubernetes.conf

    开启ipvs

    modprobe br_netfilter  #用于向内核中加载模块
    cat > /etc/sysconfig/modules/ipvs.modules<<EOF
    #!/bin/bash
    modprobe -- ip_vs
    modprobe -- ip_vs_rr
    modprobe -- ip_vs_wrr
    modprobe -- ip_vs_sh
    modprobe -- nf_conntrack
    EOF
    chmod 755 /etc/sysconfig/modules/ipvs.modules
    bash /etc/sysconfig/modules/ipvs.modules

    以上步骤所有集群机器需要全部执行。

    Sealos 部署高可用

    Sealos 相关操作只要放入其中一个节点即可,他会自动发送到其他节点

    # 下载并安装sealos, sealos是个golang的二进制工具,直接下载拷贝到bin目录即可, release页面也可下载
    wget -c https://sealyun-home.oss-cn-beijing.aliyuncs.com/sealos/latest/sealos && \
    chmod +x sealos && mv sealos /usr/bin
    
    # 下载离线资源包
    wget -c https://sealyun.oss-cn-beijing.aliyuncs.com/05a3db657821277f5f3b92d834bbaf98-v1.22.0/kube1.22.0.tar.gz
    
    #安装集群
    sealos init --passwd '12344' \
        --master 192.168.234.136  --master 192.168.234.137  --master 192.168.234.138 \
        --node 192.168.234.139 \
        --pkg-url /opt/kube1.22.0.tar.gz \
        --version v1.22.0 | tee /opt/sealosinit.log

    节点查看

    #kube-scheduler 状态查看
    kubectl  get endpoints kube-scheduler -n kube-system -o yaml
    #kube-controller-manager 状态查看
    kubectl  get endpoints kube-controller-manager -n kube-system -o yaml

    Sealos 相关命令

    增加 Master 节点

    sealos join --master 192.168.0.6 --master 192.168.0.7
    
    # 或者多个连续 IP
    sealos join --master 192.168.0.6-192.168.0.9

    增加 node

    sealos join --node 192.168.0.6 --node 192.168.0.7
    
    # 或者多个连续 IP
    sealos join --node 192.168.0.6-192.168.0.9

    删除指定 Master 节点

    sealos clean --master 192.168.0.6 --master 192.168.0.7
    
    # 或者多个连续 IP
    sealos clean --master 192.168.0.6-192.168.0.9

    删除指定 node 节点

    sealos clean --node 192.168.0.6 --node 192.168.0.7
    
    # 或者多个连续 IP
    sealos clean --node 192.168.0.6-192.168.0.9

    清理集群

    sealos clean --all

    备份集群

    sealos etcd save
  • K8s 常用控制器详解

    K8s 常用控制器详解

    - ReplicationController:比较原始的pod控制器,已经被废弃,由ReplicaSet替代
    - ReplicaSet:保证副本数量一直维持在期望值,并支持pod数量扩缩容,镜像版本升级
    - Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本
    - Horizontal Pod Autoscaler:可以根据集群负载自动水平调整Pod的数量,实现削峰填谷
    - DaemonSet:在集群中的指定Node上运行且仅运行一个副本,一般用于守护进程类的任务
    - Job:它创建出来的pod只要完成任务就立即退出,不需要重启或重建,用于执行一次性任务
    - Cronjob:它创建的Pod负责周期性任务控制,不需要持续后台运行
    - StatefulSet:管理有状态应用

    1、Pod

    每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类:

    • 用户程序所在的容器,数量可多可少
    • Pause容器,这是每个Pod都会有的一个根容器,它的作用有两个:
      • 可以以它为依据,评估整个Pod的健康状态
      • 可以在根容器上设置Ip地址,其它容器都此Ip(Pod IP),以实现Pod内部的网路通信

      这里是Pod内部的通讯,Pod的之间的通讯采用虚拟二层网络技术来实现,我们当前环境用的是Flannel

    1.1 Pod 资源清单

    apiVersion: v1     #必选,版本号,例如v1
    kind: Pod         #必选,资源类型,例如 Pod
    metadata:         #必选,元数据
      name: string     #必选,Pod名称
      namespace: string  #Pod所属的命名空间,默认为"default"
      labels:           #自定义标签列表
        name: string                 
    spec:  #必选,Pod中容器的详细定义
      containers:  #必选,Pod中容器列表
      - name: string   #必选,容器名称
        image: string  #必选,容器的镜像名称
        imagePullPolicy: [ Always|Never|IfNotPresent ]  #获取镜像的策略 
        command: [string]   #容器的启动命令列表,如不指定,使用打包时使用的启动命令
        args: [string]      #容器的启动命令参数列表
        workingDir: string  #容器的工作目录
        volumeMounts:       #挂载到容器内部的存储卷配置
        - name: string      #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
          mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
          readOnly: boolean #是否为只读模式
        ports: #需要暴露的端口库号列表
        - name: string        #端口的名称
          containerPort: int  #容器需要监听的端口号
          hostPort: int       #容器所在主机需要监听的端口号,默认与Container相同
          protocol: string    #端口协议,支持TCP和UDP,默认TCP
        env:   #容器运行前需设置的环境变量列表
        - name: string  #环境变量名称
          value: string #环境变量的值
        resources: #资源限制和请求的设置
          limits:  #资源限制的设置
            cpu: string     #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
            memory: string  #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
          requests: #资源请求的设置
            cpu: string    #Cpu请求,容器启动的初始可用数量
            memory: string #内存请求,容器启动的初始可用数量
        lifecycle: #生命周期钩子
            postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
            preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
        livenessProbe:  #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
          exec:         #对Pod容器内检查方式设置为exec方式
            command: [string]  #exec方式需要制定的命令或脚本
          httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
            path: string
            port: number
            host: string
            scheme: string
            HttpHeaders:
            - name: string
              value: string
          tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
             port: number
           initialDelaySeconds: 0       #容器启动完成后首次探测的时间,单位为秒
           timeoutSeconds: 0          #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
           periodSeconds: 0           #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
           successThreshold: 0
           failureThreshold: 0
           securityContext:
             privileged: false
      restartPolicy: [Always | Never | OnFailure]  #Pod的重启策略
      nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
      nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
      imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
      - name: string
      hostNetwork: false   #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
      volumes:   #在该pod上定义共享存储卷列表
      - name: string    #共享存储卷名称 (volumes类型有很多种)
        emptyDir: {}       #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
        hostPath: string   #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
          path: string                #Pod所在宿主机的目录,将被用于同期中mount的目录
        secret:          #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
          scretname: string  
          items:     
          - key: string
            path: string
        configMap:         #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
          name: string
          items:
          - key: string
            path: string

    1.2 示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: nb-pod
      labels:
        app: nginx-pod
    spec:
      # 容器,可以有多个
      containers:
      - name: busybox
        image: busybox
        # 容器拉取策略,Always、IfNotPresent、Never
        imagePullPolicy: IfNotPresent  
        # command 和 args 是为了替代 Docker 的 EntryPoint 功能
        command: ["sh", "-c", "while true;do /bin/echo $(date +%T) >> /tmp/index.html; sleep 10; done;"]
        # 使用挂载卷,并挂载到容器内的某个目录
        volumeMounts:
        - name: nginx-home
          mountPath: /tmp
      - name: nginx
        image: nginx:1.17.1
        # 生命周期钩子函数
        lifecycle:
          # 容器启动前钩子,失败了会重启容器
          postStart: 
            exec: 
              command: ["/bin/sh", "-c", "echo postStart... > /usr/share/nginx/html/index.html"]
          # 容器销毁前钩子, 执行失败会组织删除容器
          preStop:
            exec:
              command: ["/bin/sh", "-c", "echo preStop... >> /usr/share/nginx/html/index.html"]
        # 存活探针(liveness probes 存活探针,执行失败会尝试重启容器;readiness probes 就绪探针,执行失败则 k8s 不会转发流量)
        livenessProbe:
          # 1、cmd 方式
          #exec:
          #  command: ["/bin/cat","/usr/share/nginx/html/index.html"]
          # 2、tcp 方式
          #tcpSocket:
          #  port: 80 # 尝试访问 8080 端口,报错。如果替换为 80 端口则正常
          # 3、http 方式
          httpGet:  # 其实就是访问http://127.0.0.1:80/hello  
            scheme: HTTP #http或者https
            host: 127.0.0.1
            port: 80
            path: / 
        # 容器工作目录
        workingDir: /usr/share/nginx/html
        # 容器暴露的端口
        ports:
        - containerPort: 80
        # 环境变量
        env:
        - name: "username"
          value: "hausen1012"
        - name: "password"
          value: "123456"
        volumeMounts:
        - name: nginx-home
          mountPath: /usr/share/nginx/html
      # 重启策略,Always、Never、OnFailure
      restartPolicy: OnFailure 
      # pod 的调度。1、nodeName 2、nodeSelector 3、affinity (node 亲和性和 pod 亲和性) 4、node 设置污点、pod 设置容忍
      nodeName: node1
      # 是否使用宿主机网络,true 则直接显示 node 的 ip,而不是 pod 的虚拟 ip
      hostNetwork: true
      # 挂载目录 1、emptyDir: {} 2、hostPath 3、PV 和 PVC
      volumes:
      - name: nginx-home
        hostPath:
          path: /root/html 

    2、ReplicaSet (rs)

    ReplicaSet的主要作用是保证一定数量的pod正常运行,它会持续监听这些Pod的运行状态,一旦Pod发生故障,就会重启或重建。同时它还支持对pod数量的扩缩容和镜像版本的升降级。

    2.1 rs 资源清单

    apiVersion: apps/v1 # 版本号
    kind: ReplicaSet # 类型       
    metadata: # 元数据
      name: # rs名称 
      namespace: # 所属命名空间 
      labels: #标签
        controller: rs
    spec: # 详情描述
      replicas: 3 # 副本数量
      selector: # 选择器,通过它指定该控制器管理哪些pod
        matchLabels:      # Labels匹配规则
          app: nginx-pod
        matchExpressions: # Expressions匹配规则
          - {key: app, operator: In, values: [nginx-pod]}
      template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
        metadata:
          labels:
            app: nginx-pod
        spec:
          containers:
          - name: nginx
            image: nginx:1.17.1
            ports:
            - containerPort: 80

    2.2 示例

    pc-replicaset.yml

    apiVersion: apps/v1
    kind: ReplicaSet   
    metadata:
      name: pc-replicaset
    spec:
      # pod 数量
      replicas: 3
      # 管理哪些 pod
      selector: 
        matchLabels:
          app: nginx-pod
      template:
        metadata:
          labels:
            app: nginx-pod
        spec:
          containers:
          - name: nginx
            image: nginx:1.17.1

    2.3 命令

    # 创建
    kubectl create -f pc-replicaset.yml
    # 查看
    kubectl get all -o wide
    # 1、编辑调整
    kubectl edit rs pc-replicaset
    # 2、调整 pod 数量
    kubectl scale rs pc-replicaset --replicas=2
    # 3、调整镜像版本
    kubectl set image rs pc-replicaset nginx=nginx:1.17.2
    # 删除
    kubectl delete -f pc-replicaset.yml

    3、Deployment (depoly)

    为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器。值得一提的是,这种控制器并不直接管理pod,而是通过管理ReplicaSet来简介管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod。所以Deployment比ReplicaSet功能更加强大。

    Deployment主要功能有下面几个:

    • 支持ReplicaSet的所有功能
    • 支持发布的停止、继续
    • 支持滚动升级和回滚版本

    3.1 deploy 资源清单

    apiVersion: apps/v1 # 版本号
    kind: Deployment # 类型       
    metadata: # 元数据
      name: # deploy名称 
      namespace: # 所属命名空间 
      labels: #标签
        controller: deploy
    spec: # 详情描述
      replicas: 3 # 副本数量
      revisionHistoryLimit: 3 # 保留历史版本
      paused: false # 暂停部署,默认是false
      progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600
      strategy: # 策略
        type: RollingUpdate # 滚动更新策略
        rollingUpdate: # 滚动更新
          maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数
          maxUnavailable: 30% # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
      selector: # 选择器,通过它指定该控制器管理哪些pod
        matchLabels:      # Labels匹配规则
          app: nginx-pod
        matchExpressions: # Expressions匹配规则
          - {key: app, operator: In, values: [nginx-pod]}
      template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
        metadata:
          labels:
            app: nginx-pod
        spec:
          containers:
          - name: nginx
            image: nginx:1.17.1
            ports:
            - containerPort: 80

    3.2 示例

    pc-deployment.yml

    apiVersion: apps/v1
    kind: Deployment      
    metadata:
      name: pc-deployment
    spec: 
      replicas: 3
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: nginx-pod
      strategy: # 策略
        # 更新策略 1、RollingUpdate 滚动更新 2、Recreate 重建更新(先删除所有,再全部新建)
        type: RollingUpdate 
        # 滚动更新配置,最大存活 pod 数量,最大不可用的 pod 数量
        rollingUpdate:
          maxSurge: 25% 
          maxUnavailable: 25%
      template:
        metadata:
          labels:
            app: nginx-pod
        spec:
          containers:
          - name: nginx
            image: nginx:1.17.1

    3.3 命令

    # 创建
    kubectl create -f pc-deployment.yml --record=true
    # 查看
    kubectl get all -o wide
    # 1、编辑文件调整 (可以修改副本数量、镜像版本等)
    kubectl edit deploy pc-deployment
    # 2、直接调整 pod 数量
    kubectl scale deploy pc-deployment --replicas=6
    # 3、直接调整镜像版本,查看滚动更新或者重建更新
    kubectl set image deploy pc-deployment nginx=nginx:1.17.2
    # 删除
    kubectl delete -f pc-deployment.yml
    # 版本回退
    kubectl rollout:
    - status 显示当前升级状态
    - history   显示 升级历史记录
    - pause    暂停版本升级过程
    - resume   继续已经暂停的版本升级过程
    - restart    重启版本升级过程
    - undo 回滚到上一级版本(可以使用--to-revision回滚到指定版本)
    # 查看版本升级状态
    kubectl rollout status deploy pc-deployment
    # 查看升级历史
    kubectl rollout history deploy pc-deployment
    # 启动升级并暂停
    kubectl set image deploy pc-deployment nginx=nginx:1.17.1 && kubectl rollout pause deploy pc-deployment
    # 继续升级 
    kubectl rollout resume deploy pc-deployment
    # 回退上一版本
    kubectl rollout undo deploy pc-deployment
    # 回退到指定版本
    kubectl rollout undo deployment pc-deployment --to-revision=1

    4、Horizontal Pod Autoscaler(hpa)

    在前面的课程中,我们已经可以实现通过手工执行kubectl scale命令实现Pod扩容或缩容,但是这显然不符合Kubernetes的定位目标–自动化、智能化。 Kubernetes期望可以实现通过监测Pod的使用情况,实现pod数量的自动调整,于是就产生了Horizontal Pod Autoscaler(HPA)这种控制器。

    HPA可以获取每个Pod利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。其实HPA与之前的Deployment一样,也属于一种Kubernetes资源对象,它通过追踪分析RC控制的所有目标Pod的负载变化情况,来确定是否需要针对性地调整目标Pod的副本数,这是HPA的实现原理。

    4.1 准备工作

    安装 metrics-server

    方法1

    1、修改 kube-apiserver.yaml
    vim /etc/kubernetes/manifests/kube-apiserver.yaml
    在 - --enable-bootstrap-token-auth=true 下添加 - --enable-aggregator-routing=true
    2、更新 apiserver
    kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
    3、在每个机器上执行
    docker pull cnskylee/metrics-server:v0.5.0 && docker tag cnskylee/metrics-server:v0.5.0 k8s.gcr.io/metrics-server/metrics-server:v0.5.0
    4、编写 yaml 文件 components-v0.5.0.yaml
    5、启动 
    kubectl apply -f ./components-v0.5.0.yaml
    6、查看运行状态
    kubectl get pods -n kube-system| egrep 'NAME|metrics-server'
    7、测试kubectl top命令的使用
    kubectl top pods -n kube-system

    components-v0.5.0.yaml

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      labels:
        k8s-app: metrics-server
      name: metrics-server
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        k8s-app: metrics-server
        rbac.authorization.k8s.io/aggregate-to-admin: "true"
        rbac.authorization.k8s.io/aggregate-to-edit: "true"
        rbac.authorization.k8s.io/aggregate-to-view: "true"
      name: system:aggregated-metrics-reader
    rules:
    - apiGroups:
      - metrics.k8s.io
      resources:
      - pods
      - nodes
      verbs:
      - get
      - list
      - watch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        k8s-app: metrics-server
      name: system:metrics-server
    rules:
    - apiGroups:
      - ""
      resources:
      - pods
      - nodes
      - nodes/stats
      - namespaces
      - configmaps
      verbs:
      - get
      - list
      - watch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      labels:
        k8s-app: metrics-server
      name: metrics-server-auth-reader
      namespace: kube-system
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: extension-apiserver-authentication-reader
    subjects:
    - kind: ServiceAccount
      name: metrics-server
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      labels:
        k8s-app: metrics-server
      name: metrics-server:system:auth-delegator
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:auth-delegator
    subjects:
    - kind: ServiceAccount
      name: metrics-server
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      labels:
        k8s-app: metrics-server
      name: system:metrics-server
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:metrics-server
    subjects:
    - kind: ServiceAccount
      name: metrics-server
      namespace: kube-system
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        k8s-app: metrics-server
      name: metrics-server
      namespace: kube-system
    spec:
      ports:
      - name: https
        port: 443
        protocol: TCP
        targetPort: https
      selector:
        k8s-app: metrics-server
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        k8s-app: metrics-server
      name: metrics-server
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          k8s-app: metrics-server
      strategy:
        rollingUpdate:
          maxUnavailable: 0
      template:
        metadata:
          labels:
            k8s-app: metrics-server
        spec:
          containers:
          - args:
            - --cert-dir=/tmp
            - --secure-port=443
            - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
            - --kubelet-use-node-status-port
            - --metric-resolution=15s
            - --kubelet-insecure-tls
            image: k8s.gcr.io/metrics-server/metrics-server:v0.5.0
            imagePullPolicy: IfNotPresent
            livenessProbe:
              failureThreshold: 3
              httpGet:
                path: /livez
                port: https
                scheme: HTTPS
              periodSeconds: 10
            name: metrics-server
            ports:
            - containerPort: 443
              name: https
              protocol: TCP
            readinessProbe:
              failureThreshold: 3
              httpGet:
                path: /readyz
                port: https
                scheme: HTTPS
              initialDelaySeconds: 20
              periodSeconds: 10
            resources:
              requests:
                cpu: 100m
                memory: 200Mi
            securityContext:
              readOnlyRootFilesystem: true
              runAsNonRoot: true
              runAsUser: 1000
            volumeMounts:
            - mountPath: /tmp
              name: tmp-dir
          nodeSelector:
            kubernetes.io/os: linux
          priorityClassName: system-cluster-critical
          serviceAccountName: metrics-server
          volumes:
          - emptyDir: {}
            name: tmp-dir
    ---
    apiVersion: apiregistration.k8s.io/v1
    kind: APIService
    metadata:
      labels:
        k8s-app: metrics-server
      name: v1beta1.metrics.k8s.io
    spec:
      group: metrics.k8s.io
      groupPriorityMinimum: 100
      insecureSkipTLSVerify: true
      service:
        name: metrics-server
        namespace: kube-system
      version: v1beta1
      versionPriority: 100

    方法2(似乎有问题)

    # 1、下载 yaml 文件
    yum install git -y 
    git clone -b release-0.3 https://github.com/kubernetes-incubator/metrics-server 
    cd metrics-server/deploy/1.8+ 
    vim metrics-server-deployment.yaml
    # 2、按图中添加 hostNetwork 和 修改镜像、参数
    hostNetwork: true
    image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
    args:
    - --kubelet-insecure-tls
    - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
    # 3、安装metrics-server
    kubectl apply -f ./
    # 4、查看pod运行情况
    kubectl get pod -n kube-system
    # 5、查看资源使用情况
    kubectl top node
    kubectl top pod 

    post-468-6314a780e1bec

    4.2 示例

    deploy-sevice.yml

    kind: Deployment
    metadata:
      name: nginx-deploy
    spec:
      strategy: # 策略
        type: RollingUpdate # 滚动更新策略
      replicas: 1
      selector:
        matchLabels:
          app: nginx-pod
      template:
        metadata:
          labels:
            app: nginx-pod
        spec:
          containers:
          - name: nginx
            image: nginx:1.17.1
            resources: # 资源配额
              limits:  # 限制资源(上限)
                cpu: "1" # CPU限制,单位是core数
              requests: # 请求资源(下限)
                cpu: "100m"  # CPU限制,单位是core数
    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
    spec:
      selector:
        app: nginx-pod
      type: NodePort
      ports:
        - port: 80        # 本 Service 的端口
          targetPort: 80  # 容器端口
          nodePort: 31100
    

    pc-hpa.yml

    apiVersion: app/v1
    kind: HorizontalPodAutoscaler
    metadata:
      name: pc-hpa
    spec:
      minReplicas: 1  #最小pod数量
      maxReplicas: 10 #最大pod数量
      targetCPUUtilizationPercentage: 3 # CPU使用率指标
      scaleTargetRef:   # 指定要控制的nginx信息
        apiVersion:  apps/v1
        kind: Deployment
        name: nginx-deploy

    4.3 命令

    # 创建 deploy 和 hpa
    kubectl apply -f deploy-service.yml
    kubectl create -f pc-hpa.yml
    # postman 进行压测 查看 hpa 和 pod 和 deploy 的变化
    kubectl get hpa  -w
    kubectl get pod  -w
    kubectl get deploy -w

    5、DaemonSet(ds)

    DaemonSet类型的控制器可以保证在集群中的每一台(或指定)节点上都运行一个副本。一般适用于日志收集、节点监控等场景。也就是说,如果一个Pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。

    DaemonSet控制器的特点:

    • 每当向集群中添加一个节点时,指定的 Pod 副本也将添加到该节点上
    • 当节点从集群中移除时,Pod 也就被垃圾回收了

    5.1 DaemonSet 资源清单

    apiVersion: apps/v1 # 版本号
    kind: DaemonSet # 类型       
    metadata: # 元数据
      name: # rs名称 
      namespace: # 所属命名空间 
      labels: #标签
        controller: daemonset
    spec: # 详情描述
      revisionHistoryLimit: 3 # 保留历史版本
      updateStrategy: # 更新策略
        type: RollingUpdate # 滚动更新策略
        rollingUpdate: # 滚动更新
          maxUnavailable: 1 # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
      selector: # 选择器,通过它指定该控制器管理哪些pod
        matchLabels:      # Labels匹配规则
          app: nginx-pod
        matchExpressions: # Expressions匹配规则
          - {key: app, operator: In, values: [nginx-pod]}
      template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
        metadata:
          labels:
            app: nginx-pod
        spec:
          containers:
          - name: nginx
            image: nginx:1.17.1
            ports:
            - containerPort: 80

    5.2 示例

    pc-daemonset.yml

    apiVersion: apps/v1
    kind: DaemonSet      
    metadata:
      name: pc-daemonset
    spec: 
      selector:
        matchLabels:
          app: nginx-pod
      template:
        metadata:
          labels:
            app: nginx-pod
        spec:
          containers:
          - name: nginx
            image: nginx:1.17.1

    5.3 命令

    # 创建
    kubectl create -f  pc-daemonset.yml
    # 查看 ds
    kubectl get ds -o wide
    # 查看pod,发现在每个Node上都运行一个pod
    kubectl get pods -o wide
    # 删除
    kubectl delete -f  pc-daemonset.yml

    6、Job

    Job,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务。Job特点如下:

    • 当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
    • 当成功结束的pod达到指定的数量时,Job将完成执行

    6.1 Job 资源清单

    apiVersion: batch/v1 # 版本号
    kind: Job # 类型       
    metadata: # 元数据
      name: # rs名称 
      namespace: # 所属命名空间 
      labels: #标签
        controller: job
    spec: # 详情描述
      completions: 1 # 指定job需要成功运行Pods的次数。默认值: 1
      parallelism: 1 # 指定job在任一时刻应该并发运行Pods的数量。默认值: 1
      activeDeadlineSeconds: 30 # 指定job可运行的时间期限,超过时间还未结束,系统将会尝试进行终止。
      backoffLimit: 6 # 指定job失败后进行重试的次数。默认是6
      manualSelector: true # 是否可以使用selector选择器选择pod,默认是false
      selector: # 选择器,通过它指定该控制器管理哪些pod
        matchLabels:      # Labels匹配规则
          app: counter-pod
        matchExpressions: # Expressions匹配规则
          - {key: app, operator: In, values: [counter-pod]}
      template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
        metadata:
          labels:
            app: counter-pod
        spec:
          restartPolicy: Never # 重启策略只能设置为Never或者OnFailure
          containers:
          - name: counter
            image: busybox:1.30
            command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 2;done"]

    6.2 示例

    pc-job.yml

    apiVersion: batch/v1
    kind: Job      
    metadata:
      name: pc-job
    spec:
      # 指定job需要成功运行Pods的次数为6
      completions: 6
      # 指定job并发运行Pods的数量为3
      parallelism: 3
      manualSelector: true
      selector:
        matchLabels:
          app: counter-pod
      template:
        metadata:
          labels:
            app: counter-pod
        spec:
          restartPolicy: Never
          containers:
          - name: counter
            image: busybox:1.30
            command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done"]

    6.3 命令

    # 创建
    kubectl create -f pc-job.yml
    # 查看
    kubectl get job -o wide  -w
    # 通过观察pod状态可以看到,pod每次运行3个,总共运行6次
    kubectl get pods -w
    # 删除
    kubectl delete -f pc-job.yml

    7、CronJob

    CronJob控制器以 Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点重复运行的方式。也就是说,CronJob可以在特定的时间点(反复的)去运行job任务

    7.1 CronJob资源清单

    apiVersion: batch/v1beta1 # 版本号
    kind: CronJob # 类型       
    metadata: # 元数据
      name: # rs名称 
      namespace: # 所属命名空间 
      labels: #标签
        controller: cronjob
    spec: # 详情描述
      schedule: # cron格式的作业调度运行时间点,用于控制任务在什么时间执行
      concurrencyPolicy: # 并发执行策略,用于定义前一次作业运行尚未完成时是否以及如何运行后一次的作业
      failedJobHistoryLimit: # 为失败的任务执行保留的历史记录数,默认为1
      successfulJobHistoryLimit: # 为成功的任务执行保留的历史记录数,默认为3
      startingDeadlineSeconds: # 启动作业错误的超时时长
      jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象;下面其实就是job的定义
        metadata:
        spec:
          completions: 1
          parallelism: 1
          activeDeadlineSeconds: 30
          backoffLimit: 6
          manualSelector: true
          selector:
            matchLabels:
              app: counter-pod
            matchExpressions: 规则
              - {key: app, operator: In, values: [counter-pod]}
          template:
            metadata:
              labels:
                app: counter-pod
            spec:
              restartPolicy: Never 
              containers:
              - name: counter
                image: busybox:1.30
                command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 20;done"]
    需要重点解释的几个选项:
    schedule: cron表达式,用于指定任务的执行时间
        */1    *      *    *     *
        <分钟> <小时> <日> <月份> <星期>
    
        分钟 值从 0 到 59.
        小时 值从 0 到 23.
        日 值从 1 到 31.
        月 值从 1 到 12.
        星期 值从 0 到 6, 0 代表星期日
        多个时间可以用逗号隔开; 范围可以用连字符给出;*可以作为通配符; /表示每...
    concurrencyPolicy:
        Allow:   允许Jobs并发运行(默认)
        Forbid:  禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行
        Replace: 替换,取消当前正在运行的作业并用新作业替换它

    7.2 示例

    pc-cronjob.yml

    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name: pc-cronjob
      labels:
        controller: cronjob
    spec:
      schedule: "*/1 * * * *"
      jobTemplate:
        metadata:
        spec:
          template:
            spec:
              restartPolicy: Never
              containers:
              - name: counter
                image: busybox:1.30
                command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done"]

    7.3 命令

    # 创建
    kubectl create -f pc-cronjob.yml
    # 查看cronjob
    kubectl get cronjobs
    # 查看 job
    kubectl get jobs
    # 查看pod
    kubectl get pod
    # 删除
    kubectl  delete -f pc-cronjob.yml

    扩展 Service(svc)

    svc 资源清单文件

    apiVersion: v1  # 资源版本
    kind: Service  # 资源类型
    metadata: # 元数据
      name: service # 资源名称
      namespace: dev # 命名空间
    spec: # 描述
      selector: # 标签选择器,用于确定当前service代理哪些pod
        app: nginx
      type: # Service类型,指定service的访问方式
      clusterIP:  # 虚拟服务的ip地址
      sessionAffinity: # session亲和性,支持ClientIP、None两个选项
      ports: # 端口信息
        - protocol: TCP 
          port: 3017  # service端口
          targetPort: 5003 # pod端口
          nodePort: 31122 # 主机端口
    • ClusterIP:默认值,它是Kubernetes系统自动分配的虚拟IP,只能在集群内部访问
    • NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务
    • LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持
    • ExternalName: 把集群外部的服务引入集群内部,直接使用
  • k8s双向证书认证实战-创建基于rbac认证的角色并绑定用户

    k8s双向证书认证实战-创建基于rbac认证的角色并绑定用户

    一、认证管理

    kubernetes集群安全的关键点在于如何识别并认证客户端身份,它提供了3种客户端身份认证方式:

    1. HTTP Base认证

    通过用户名+密码的方式进行认证。

    这种方式是把“用户名:密码”用BASE64算法进行编码后的字符串放在HTTP请求中的Header的Authorization域里面发送给服务端。服务端收到后进行解码,获取用户名和密码,然后进行用户身份认证的过程。

    2. HTTP Token认证

    通过一个Token来识别合法用户。

    这种认证方式是用一个很长的难以被模仿的字符串–Token来表明客户端身份的一种方式。每个Token对应一个用户名,当客户端发起API调用请求的时候,需要在HTTP的Header中放入Token,API Server接受到Token后会和服务器中保存的Token进行比对,然后进行用户身份认证的过程。

    3. HTTPS证书认证

    基于CA根证书签名的双向数字证书认证方式。

    这种认证方式是安全性最高的一种方式,但是同时也是操作起来最麻烦的一种方式。

    post-799-63ae43dc0f58e

    HTTPS认证大体分为3个过程:

    1. 证书申请和下发

    HTTPS通信双方的服务器向CA机构申请证书,CA机构下发根证书、服务端证书及私钥给申请者

    1. 客户端和服务端的双向认证
    • 客户端向服务器端发起请求,服务端下发自己的证书给客户端,客户端接收到证书后,通过私钥解密证书,在证书中获得服务端的公钥,客户端利用服务器端的公钥认证证书中的信息,如果一致,则认可这个服务器。
    • 客户端发送自己的证书给服务器端,服务端接收到证书后,通过私钥解密证书,在证书中获得客户端的公钥,并用该公钥认证证书信息,确认客户端是否合法
    1. 服务器端和客户端进行通信

    服务器端和客户端协商好加密方案后,客户端会产生一个随机的秘钥并加密,然后发送到服务器端。服务器端接收这个秘钥后,双方接下来通信的所有内容都通过该随机秘钥加密。

    二、创建用户证书

    1. 生成客户端私钥

    # 进入 k8s 存放证书的目录
    cd /etc/kubernetes/pki/
    # 生成私钥
    umask 077;openssl genrsa -out devman.key 2048

    2. 生成证书请求

    openssl req -new -key devman.key -out devman.csr -subj "/CN=devman/O=devgroup"

    申请的用户是devman,组是devgroup。

    3. 签属证书

    openssl x509 -req -in devman.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out devman.crt -days 3650

    三、配置集群上下文

    # 1. 设置集群(这一步不需要,使用默认的集群即可)
    # kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.18.100:6443
    
    # 2. 创建一个用户 devman,并指定他的证书和私钥的位置。
    kubectl config set-credentials devman --embed-certs=true --client-certificate=/etc/kubernetes/pki/devman.crt --client-key=/etc/kubernetes/pki/devman.key
    
    # 3. 设置上下文(创建特定集群和用户的绑定关系,切换上下文相当于切换了用户和集群)
    kubectl config set-context devman@kubernetes --cluster=kubernetes --user=devman
    
    # 4. 创建 namespace
    kubectl create ns dev
    
    # 5. 切换到 devman 用户
    kubectl config use-context devman@kubernetes

    此时如果执行 kubectl get pods -n dev 会提示没有权限,这个是因为还没授权,接下来通过创建角色和角色绑定用户 devman 进行授权。

    四、创建角色和角色绑定

    1. 切换到admin账户

    kubectl config use-context kubernetes-admin@kubernetes

    2. 创建角色和角色绑定

    # 创建请求文件
    cat > dev-role.yaml<<EOF
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: dev-role
      namespace: dev
    rules:
      - apiGroups: [""] # 支持的API组列表,""空字符串,表示核心API群
        resources: ["pods"] # 支持的资源对象列表
        verbs: ["create","get","watch","list"]
    
    ---
    
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: authorization-role-binding
      namespace: dev
    subjects:
      - kind: User
        name: devman
        apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role
      name: dev-role
      apiGroup: rbac.authorization.k8s.io
    EOF
    # 生成角色
    kubectl apply -f dev-role.yaml

    五、测试

    1. 切换到devman账户

    kubectl config use-context devman@kubernetes

    2. 创建并获取 pod

    # 创建nginx
    kubectl run nginx-pod --image="nginx" -n dev
    # 获取pod列表
    kubectl get pod -n dev
    # 获取default名称空间列表 -> 没有权限
    kubectl get pod
    #Error from server (Forbidden): pods is forbidden: User "devman" cannot list resource "pods" in API group "" in the namespace "default"
  • K8s 存储详解-包括pv、pvc、confmap、secret

    K8s 存储详解-包括pv、pvc、confmap、secret

    一、基本存储

    1 EmptyDir

    EmptyDir是最基础的Volume类型,一个EmptyDir就是Host上的一个空目录。

    EmptyDir是在Pod被分配到Node时创建的,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为kubernetes会自动分配一个目录,当Pod销毁时, EmptyDir中的数据也会被永久删除。 EmptyDir用途如下:

    • 临时空间,例如用于某些应用程序运行时所需的临时目录,且无须永久保留
    • 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)

    接下来,通过一个容器之间文件共享的案例来使用一下EmptyDir。

    在一个Pod中准备两个容器nginx和busybox,然后声明一个Volume分别挂在到两个容器的目录中,然后nginx容器负责向Volume中写日志,busybox中通过命令将日志内容读到控制台。

    post-690-635b3c02413d9

    1.1 示例

    volume-emptydir.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: volume-emptydir
      namespace: dev
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
        volumeMounts:  # 将logs-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
        - name: logs-volume
          mountPath: /var/log/nginx
      - name: busybox
        image: busybox:1.30
        command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始命令,动态读取指定文件中内容
        volumeMounts:  # 将logs-volume 挂在到busybox容器中,对应的目录为 /logs
        - name: logs-volume
          mountPath: /logs
      volumes: # 声明volume, name为logs-volume,类型为emptyDir
      - name: logs-volume
        emptyDir: {}

    1.2 命令

    # 创建Pod
    [root@k8s-master01 ~]# kubectl create -f volume-emptydir.yaml
    pod/volume-emptydir created
    
    # 查看pod
    [root@k8s-master01 ~]# kubectl get pods volume-emptydir -n dev -o wide
    NAME                  READY   STATUS    RESTARTS   AGE      IP       NODE   ......
    volume-emptydir       2/2     Running   0          97s   10.42.2.9   node1  ......
    
    # 通过podIp访问nginx
    [root@k8s-master01 ~]# curl 10.42.2.9
    ......
    
    # 通过kubectl logs命令查看指定容器的标准输出
    [root@k8s-master01 ~]# kubectl logs -f volume-emptydir -n dev -c busybox
    10.42.1.0 - - [27/Jun/2021:15:08:54 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"

    2 HostPath

    EmptyDir中数据不会被持久化,它会随着Pod的结束而销毁,如果想简单的将数据持久化到主机中,可以选择HostPath。

    HostPath就是将Node主机中一个实际目录挂在到Pod中,以供容器使用,这样的设计就可以保证Pod销毁了,但是数据依据可以存在于Node主机上。

    post-690-635b3c026ec68

    2.1 示例

    volume-hostpath.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: volume-hostpath
      namespace: dev
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
        volumeMounts:
        - name: logs-volume
          mountPath: /var/log/nginx
      - name: busybox
        image: busybox:1.30
        command: ["/bin/sh","-c","tail -f /logs/access.log"]
        volumeMounts:
        - name: logs-volume
          mountPath: /logs
      volumes:
      - name: logs-volume
        hostPath:
          path: /root/logs
          type: DirectoryOrCreate  # 目录存在就使用,不存在就先创建后使用

    关于type的值的一点说明:
    DirectoryOrCreate 目录存在就使用,不存在就先创建后使用
    Directory 目录必须存在
    FileOrCreate 文件存在就使用,不存在就先创建后使用
    File 文件必须存在
    Socket unix套接字必须存在
    CharDevice 字符设备必须存在
    BlockDevice 块设备必须存在

    2.2 命令

    # 创建Pod
    [root@k8s-master01 ~]# kubectl create -f volume-hostpath.yaml
    pod/volume-hostpath created
    
    # 查看Pod
    [root@k8s-master01 ~]# kubectl get pods volume-hostpath -n dev -o wide
    NAME                  READY   STATUS    RESTARTS   AGE   IP             NODE   ......
    pod-volume-hostpath   2/2     Running   0          16s   10.42.2.10     node1  ......
    
    #访问nginx
    [root@k8s-master01 ~]# curl 10.42.2.10
    
    [root@k8s-master01 ~]# kubectl logs -f volume-emptydir -n dev -c busybox
    
    # 接下来就可以去host的/root/logs目录下查看存储的文件了
    ###  注意: 下面的操作需要到Pod所在的节点运行(案例中是node1)
    [root@node1 ~]# ls /root/logs/
    access.log  error.log
    
    # 同样的道理,如果在此目录下创建一个文件,到容器中也是可以看到的

    3 NFS

    HostPath可以解决数据持久化的问题,但是一旦Node节点故障了,Pod如果转移到了别的节点,又会出现问题了,此时需要准备单独的网络存储系统,比较常用的用NFS、CIFS。

    NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node跟NFS的对接没问题,数据就可以成功访问。

    post-690-635b3c02a1d4c

    3.1 安装 nfs

    1)首先要准备nfs的服务器,这里为了简单,直接是master节点做nfs服务器

    # 在nfs上安装nfs服务
    [root@nfs ~]# yum install nfs-utils -y
    
    # 准备一个共享目录
    [root@nfs ~]# mkdir /root/data/nfs -pv
    
    # 将共享目录以读写权限暴露给172.21.9.0/24网段中的所有主机
    [root@nfs ~]# vim /etc/exports
    [root@nfs ~]# more /etc/exports
    /root/data/nfs     172.21.9.0/24(rw,no_root_squash)
    
    # 启动nfs服务
    [root@nfs ~]# systemctl restart nfs

    2)接下来,要在的每个node节点上都安装下nfs,这样的目的是为了node节点可以驱动nfs设备

    # 在node上安装nfs服务,注意不需要启动
    [root@k8s-master01 ~]# yum install -y nfs-utils

    3.2 示例

    volume-nfs.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: volume-nfs
      namespace: dev
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
        volumeMounts:
        - name: logs-volume
          mountPath: /var/log/nginx
      - name: busybox
        image: busybox:1.30
        command: ["/bin/sh","-c","tail -f /logs/access.log"]
        volumeMounts:
        - name: logs-volume
          mountPath: /logs
      volumes:
      - name: logs-volume
        nfs:
          server: 172.21.9.100  #nfs服务器地址
          path: /root/data/nfs #共享文件路径

    3.3 命令

    # 创建pod
    [root@k8s-master01 ~]# kubectl create -f volume-nfs.yaml
    pod/volume-nfs created
    
    # 查看pod
    [root@k8s-master01 ~]# kubectl get pods volume-nfs -n dev
    NAME                  READY   STATUS    RESTARTS   AGE
    volume-nfs        2/2     Running   0          2m9s
    
    # 查看nfs服务器上的共享目录,发现已经有文件了
    [root@k8s-master01 ~]# ls /root/data/nfs/
    access.log  error.log

    二、高级存储

    前面已经学习了使用NFS提供存储,此时就要求用户会搭建NFS系统,并且会在yaml配置nfs。由于kubernetes支持的存储系统有很多,要求客户全都掌握,显然不现实。为了能够屏蔽底层存储实现的细节,方便用户使用, kubernetes引入PV和PVC两种资源对象。

    • PV(Persistent Volume)是持久化卷的意思,是对底层的共享存储的一种抽象。一般情况下PV由kubernetes管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。
    • PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC其实就是用户向kubernetes系统发出的一种资源需求申请。

    post-690-635b3c02d02b6

    使用了PV和PVC之后,工作可以得到进一步的细分:

    • 存储:存储工程师维护
    • PV: kubernetes管理员维护
    • PVC:kubernetes用户维护

    1 PV

    1.1 资源清单

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv2
    spec:
      nfs: # 存储类型,与底层真正存储对应
      capacity:  # 存储能力,目前只支持存储空间的设置
        storage: 2Gi
      accessModes:  # 访问模式
      storageClassName: # 存储类别
      persistentVolumeReclaimPolicy: # 回收策略

    PV 的关键配置参数说明:

    • 存储类型

      底层实际存储的类型,kubernetes支持多种存储类型,每种存储类型的配置都有所差异

    • 存储能力(capacity)

    目前只支持存储空间的设置( storage=1Gi ),不过未来可能会加入IOPS、吞吐量等指标的配置

    • 访问模式(accessModes)

      用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

      • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
      • ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
      • ReadWriteMany(RWX):读写权限,可以被多个节点挂载

      需要注意的是,底层不同的存储类型可能支持的访问模式不同

    • 回收策略(persistentVolumeReclaimPolicy)

      当PV不再被使用了之后,对其的处理方式。目前支持三种策略:

      • Retain (保留) 保留数据,需要管理员手工清理数据
      • Recycle(回收) 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
      • Delete (删除) 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务

      需要注意的是,底层不同的存储类型可能支持的回收策略不同

    • 存储类别

      PV可以通过storageClassName参数指定一个存储类别

      • 具有特定类别的PV只能与请求了该类别的PVC进行绑定
      • 未设定类别的PV则只能与不请求任何类别的PVC进行绑定
    • 状态(status)

      一个 PV 的生命周期中,可能会处于4中不同的阶段:

      • Available(可用): 表示可用状态,还未被任何 PVC 绑定
      • Bound(已绑定): 表示 PV 已经被 PVC 绑定
      • Released(已释放): 表示 PVC 被删除,但是资源还未被集群重新声明
      • Failed(失败): 表示该 PV 的自动回收失败

    1.2 准备 NFS 环境

    # 创建目录
    [root@nfs ~]# mkdir /root/data/{pv1,pv2,pv3} -pv
    
    # 暴露服务
    [root@nfs ~]# more /etc/exports
    /root/data/pv1     172.21.9.0/24(rw,no_root_squash)
    /root/data/pv2     172.21.9.0/24(rw,no_root_squash)
    /root/data/pv3     172.21.9.0/24(rw,no_root_squash)
    
    # 重启服务
    [root@nfs ~]#  systemctl restart nfs

    1.3 示例

    pv.yaml

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name:  pv1
    spec:
      capacity:
        storage: 1Gi
      accessModes:
      - ReadWriteMany
      persistentVolumeReclaimPolicy: Retain
      nfs:
        path: /root/data/pv1
        server: 172.21.9.100
    
    ---
    
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name:  pv2
    spec:
      capacity:
        storage: 2Gi
      accessModes:
      - ReadWriteMany
      persistentVolumeReclaimPolicy: Retain
      nfs:
        path: /root/data/pv2
        server: 172.21.9.100
    ---
    
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name:  pv3
    spec:
      capacity:
        storage: 3Gi
      accessModes:
      - ReadWriteMany
      persistentVolumeReclaimPolicy: Retain
      nfs:
        path: /root/data/pv3
        server: 172.21.9.100

    1.4 命令

    # 创建 pv
    [root@k8s-master01 ~]# kubectl create -f pv.yaml
    persistentvolume/pv1 created
    persistentvolume/pv2 created
    persistentvolume/pv3 created
    
    # 查看pv
    [root@k8s-master01 ~]# kubectl get pv -o wide
    NAME   CAPACITY   ACCESS MODES  RECLAIM POLICY  STATUS      AGE   VOLUMEMODE
    pv1    1Gi        RWX            Retain        Available    10s   Filesystem
    pv2    2Gi        RWX            Retain        Available    10s   Filesystem
    pv3    3Gi        RWX            Retain        Available    9s    Filesystem

    2 PVC

    2.1 资源清单

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: pvc
      namespace: dev
    spec:
      accessModes: # 访问模式
      selector: # 采用标签对PV选择
      storageClassName: # 存储类别
      resources: # 请求空间
        requests:
          storage: 5Gi

    PVC 的关键配置参数说明:

    • 访问模式(accessModes)

    用于描述用户应用对存储资源的访问权限

    • 选择条件(selector)

      通过Label Selector的设置,可使PVC对于系统中己存在的PV进行筛选

    • 存储类别(storageClassName)

      PVC在定义时可以设定需要的后端存储的类别,只有设置了该class的pv才能被系统选出

    • 资源请求(Resources )

      描述对存储资源的请求

    2.2 创建 PVC

    pvc.yaml

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: pvc1
    spec:
      accessModes: 
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: pvc2
    spec:
      accessModes: 
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: pvc3
    spec:
      accessModes: 
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
    # 创建pvc
    [root@k8s-master01 ~]# kubectl create -f pvc.yaml
    persistentvolumeclaim/pvc1 created
    persistentvolumeclaim/pvc2 created
    persistentvolumeclaim/pvc3 created
    
    # 查看pvc
    [root@k8s-master01 ~]# kubectl get pvc -o wide
    NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE   VOLUMEMODE
    pvc1   Bound    pv1      1Gi        RWX                           15s   Filesystem
    pvc2   Bound    pv2      2Gi        RWX                           15s   Filesystem
    pvc3   Bound    pv3      3Gi        RWX                           15s   Filesystem
    
    # 查看pv
    [root@k8s-master01 ~]# kubectl get pv -o wide
    NAME  CAPACITY ACCESS MODES  RECLAIM POLICY  STATUS    CLAIM       AGE     VOLUMEMODE
    pv1    1Gi        RWx        Retain          Bound    dev/pvc1    3h37m    Filesystem
    pv2    2Gi        RWX        Retain          Bound    dev/pvc2    3h37m    Filesystem
    pv3    3Gi        RWX        Retain          Bound    dev/pvc3    3h37m    Filesystem

    2.3 创建pods.yaml, 使用pv

    pods.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod1
    spec:
      containers:
      - name: busybox
        image: busybox:1.30
        command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 10; done;"]
        volumeMounts:
        - name: volume
          mountPath: /root/
      volumes:
        - name: volume
          persistentVolumeClaim:
            claimName: pvc1
            readOnly: false
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod2
    spec:
      containers:
      - name: busybox
        image: busybox:1.30
        command: ["/bin/sh","-c","while true;do echo pod2 >> /root/out.txt; sleep 10; done;"]
        volumeMounts:
        - name: volume
          mountPath: /root/
      volumes:
        - name: volume
          persistentVolumeClaim:
            claimName: pvc2
            readOnly: false
    # 创建pod
    [root@k8s-master01 ~]# kubectl create -f pods.yaml
    pod/pod1 created
    pod/pod2 created
    
    # 查看pod
    [root@k8s-master01 ~]# kubectl get pods -o wide
    NAME   READY   STATUS    RESTARTS   AGE   IP            NODE   
    pod1   1/1     Running   0          14s   10.244.1.69   node1   
    pod2   1/1     Running   0          14s   10.244.1.70   node1  
    
    # 查看pvc
    [root@k8s-master01 ~]# kubectl get pvc -o wide
    NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES      AGE   VOLUMEMODE
    pvc1   Bound    pv1      1Gi        RWX               94m   Filesystem
    pvc2   Bound    pv2      2Gi        RWX               94m   Filesystem
    pvc3   Bound    pv3      3Gi        RWX               94m   Filesystem
    
    # 查看pv
    [root@k8s-master01 ~]# kubectl get pv -o wide
    NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM       AGE     VOLUMEMODE
    pv1    1Gi        RWX            Retain           Bound    dev/pvc1    5h11m   Filesystem
    pv2    2Gi        RWX            Retain           Bound    dev/pvc2    5h11m   Filesystem
    pv3    3Gi        RWX            Retain           Bound    dev/pvc3    5h11m   Filesystem
    
    # 查看nfs中的文件存储
    [root@nfs ~]# more /root/data/pv1/out.txt
    node1
    node1
    [root@nfs ~]# more /root/data/pv2/out.txt
    node2
    node2

    3 生命周期

    PVC和PV是一一对应的,PV和PVC之间的相互作用遵循以下生命周期:

    • 资源供应:管理员手动创建底层存储和PV
    • 资源绑定:用户创建PVC,kubernetes负责根据PVC的声明去寻找PV,并绑定

      在用户定义好PVC之后,系统将根据PVC对存储资源的请求在已存在的PV中选择一个满足条件的

      • 一旦找到,就将该PV与用户定义的PVC进行绑定,用户的应用就可以使用这个PVC了
      • 如果找不到,PVC则会无限期处于Pending状态,直到等到系统管理员创建了一个符合其要求的PV

      PV一旦绑定到某个PVC上,就会被这个PVC独占,不能再与其他PVC进行绑定了

    • 资源使用:用户可在pod中像volume一样使用pvc

      Pod使用Volume的定义,将PVC挂载到容器内的某个路径进行使用。

    • 资源释放:用户删除pvc来释放pv

      当存储资源使用完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为“已释放”,但还不能立刻与其他PVC进行绑定。通过之前PVC写入的数据可能还被留在存储设备上,只有在清除之后该PV才能再次使用。

    • 资源回收:kubernetes根据pv设置的回收策略进行资源的回收

      对于PV,管理员可以设定回收策略,用于设置与之绑定的PVC释放资源之后如何处理遗留数据的问题。只有PV的存储空间完成回收,才能供新的PVC绑定和使用
      post-690-635b3c030f115

    三、配置存储

    1 ConfigMap

    ConfigMap是一种比较特殊的存储卷,它的主要作用是用来存储配置信息的。

    1.1 创建 configmap

    configmap.yaml

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: configmap
    data:
      info: |
        username:admin
        password:123456
    # 创建configmap
    [root@k8s-master01 ~]# kubectl create -f configmap.yaml
    configmap/configmap created
    
    # 查看configmap详情
    [root@k8s-master01 ~]# kubectl describe cm configmap
    Name:         configmap
    Namespace:    dev
    Labels:       <none>
    Annotations:  <none>
    
    Data
    ====
    info:
    ----
    username:admin
    password:123456
    
    Events:  <none>

    1.2 挂载 configmap

    pod-configmap.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-configmap
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        volumeMounts: # 将configmap挂载到目录
        - name: config
          mountPath: /configmap/config
      volumes: # 引用configmap
      - name: config
        configMap:
          name: configmap
    # 创建pod
    [root@k8s-master01 ~]# kubectl create -f pod-configmap.yaml
    pod/pod-configmap created
    
    # 查看pod
    [root@k8s-master01 ~]# kubectl get pod pod-configmap -n dev
    NAME            READY   STATUS    RESTARTS   AGE
    pod-configmap   1/1     Running   0          6s
    
    #进入容器
    [root@k8s-master01 ~]# kubectl exec -it pod-configmap /bin/sh
    # cd /configmap/config/
    # ls
    info
    # more info
    username:admin
    password:123456
    
    # 可以看到映射已经成功,每个configmap都映射成了一个目录
    # key--->文件     value---->文件中的内容
    # 此时如果更新configmap的内容, 容器中的值也会动态更新

    2 Secret

    2.1 首先使用base64对数据进行编码

    [root@k8s-master01 ~]# echo -n 'admin' | base64 #准备username
    YWRtaW4=
    [root@k8s-master01 ~]# echo -n '123456' | base64 #准备password
    MTIzNDU2

    2.2 创建 secret

    secret.yaml

    apiVersion: v1
    kind: Secret
    metadata:
      name: secret
    type: Opaque
    data:
      username: YWRtaW4=
      password: MTIzNDU2
    # 创建secret
    [root@k8s-master01 ~]# kubectl create -f secret.yaml
    secret/secret created
    
    # 查看secret详情
    [root@k8s-master01 ~]# kubectl describe secret secret
    Name:         secret
    Namespace:    dev
    Labels:       <none>
    Annotations:  <none>
    Type:  Opaque
    Data
    ====
    password:  6 bytes
    username:  5 bytes

    2.3 使用 secret

    pod-secret.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-secret
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        volumeMounts: # 将secret挂载到目录
        - name: config
          mountPath: /secret/config
      volumes:
      - name: config
        secret:
          secretName: secret
    # 创建pod
    [root@k8s-master01 ~]# kubectl create -f pod-secret.yaml
    pod/pod-secret created
    
    # 查看pod
    [root@k8s-master01 ~]# kubectl get pod pod-secret
    NAME            READY   STATUS    RESTARTS   AGE
    pod-secret      1/1     Running   0          2m28s
    
    # 进入容器,查看secret信息,发现已经自动解码了
    [root@k8s-master01 ~]# kubectl exec -it pod-secret /bin/sh
    / # ls /secret/config/
    password  username
    / # more /secret/config/username
    admin
    / # more /secret/config/password
    123456

    至此,已经实现了利用secret实现了信息的编码。

  • k8s 手动管理 ServiceAccount 的 Secret

    k8s 手动管理 ServiceAccount 的 Secret

    v1.22 之前的 Kubernetes 版本会自动创建凭据访问 Kubernetes API。 这种更老的机制基于先创建令牌 Secret,然后将其挂载到正运行的 Pod 中。

    而更新的版本的 K8s 则不会直接创建,使用kubectl describe sa xx命令可以看见 Tokens 的值为 none,此时需要进行手动创建 Sercet。

    假设现在有一个名为 test 的 serviceAccount,所处的命名空间是 dev,则进行如下操作即可获取到 test 用户的 token。

    # 设置 serviceAccount 环境变量
    export serviceAccount=test
    # 设置命名空间环境变量
    export namespace=dev
    
    # 创建通用文件
    cat > sa.yaml<<EOF
    apiVersion: v1
    kind: Secret
    metadata:
      name: sa-token
      namespace: default
      annotations:
        kubernetes.io/service-account.name: sa
    type: kubernetes.io/service-account-token
    EOF
    # 修改文件名称和内容
    mv sa.yaml sa-${serviceAccount}.yaml && \
    sed -i "s/sa/${serviceAccount}/g" sa-${serviceAccount}.yaml && \
    sed -i "s/default/${namespace}/g" sa-${serviceAccount}.yaml
    
    # 创建 Secret
    kubectl apply -f sa-${serviceAccount}.yaml

    查看生成的 token,如下图:

    post-801-63ae71da59f9d

  • k8s 创建可视化管理面板 dashboard

    k8s 创建可视化管理面板 dashboard

    kubernetes 开发了一个基于web的用户界面(Dashboard)。用户可以使用Dashboard部署容器化的应用,还可以监控应用的状态,执行故障排查以及管理kubernetes中各种资源。

    本次安装的环境:k8s 集群版本为 v1.25,dashboard 的版本是 v2.7.0。

    1. 下载 yaml 文件

    wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

    2. 修改 Service

    这一步主要是为了暴露 dashboard 服务端口。

    kind: Service
    apiVersion: v1
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
      name: kubernetes-dashboard
      namespace: kubernetes-dashboard
    spec:
      type: NodePort  # 新增
      ports:
        - port: 443
          targetPort: 8443
          nodePort: 30010  # 新增
      selector:
        k8s-app: kubernetes-dashboard

    修改 Service 类型为 NodePort 类型,然后指定端口为 30010。

    3. 创建 dashboard

    # 创建
    kubectl apply -f recommended.yaml
    # 查看 pod 状态
    kubectl get pod -n kubernetes-dashboard

    4. 创建用户

    创建一个 dashboard-admin 用户,并绑定角色 cluster-admin,用以获取登录的 token。

    # 创建 dashboard-admin 用户
    kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
    # 绑定 clusterrolebinding
    kubectl create clusterrolebinding dashboard-admin-rb --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin

    5. 创建 token

    在以前版本的 kubernetes 中,进行了创建 serviceaccount 会自动生成一个 Secret 里面存放 token 值,但是新版本不会这样做了。可以参考之前的文章 k8s 手动管理 ServiceAccount 的 Secret

    # dashboard-admin-token.yaml
    cat > dashboard-admin-token.yaml<<EOF
    kind: Secret
    metadata:
      name: dashboard-admin-secret
      namespace: kubernetes-dashboard
      annotations:
        kubernetes.io/service-account.name: dashboard-admin
    type: kubernetes.io/service-account-token
    EOF
    # 创建 token
    kubectl apply -f dashboard-admin-token.yaml

    6. 获取 token 登录页面

    [root@master sa]# kubectl describe secret dashboard-admin-secret -n kubernetes-dashboard
    Name:         dashboard-admin-secret
    Namespace:    kubernetes-dashboard
    Labels:       <none>
    Annotations:  kubernetes.io/service-account.name: dashboard-admin
                  kubernetes.io/service-account.uid: 86a0f643-c6e5-44a3-93f1-cd28aa090be9
    
    Type:  kubernetes.io/service-account-token
    
    Data
    ====
    token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IlJlaHp4U0syRTJzSWYzcnlxV2NXX0NCWUhpampSWjU4bjdtdG1yeXBuX3cifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tc2VjcmV0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImRhc2hib2FyZC1hZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6Ijg2YTBmNjQzLWM2ZTUtNDRhMy05M2YxLWNkMjhhYTA5MGJlOSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDpkYXNoYm9hcmQtYWRtaW4ifQ.kwMoelHZYpo8-S27-LhfcA75kwUj_xRE7hN2bshfMcyo8X1VvHoq7UQ_qk97NwFXMSF93wzdfcr0mVn12czaQkYxlLcdE6YVNNl8wcUq21YPMJmrwxj2yCR5fPUqh_2zAUJcVNlSbis3MCO_TiN3t5ljVMyWpeBXYbcxd7Sh_wcGNmgi6jb1u_7lnZL1XOd2jq9Wm2QupqQKtF_s-U80RIYE20g8pR-Qz9u65W-bU__khtIkJGMsWuyLUN-G8Jnx90ypXs3a18CaAfdaH6SVOJcWTnRisX1QhlUnP4OsO8cQ40r1gUWmDYQJr-mqBJ_MaYjBA5XnTm9ABtO5FIu36Q
    ca.crt:     1070 bytes
    namespace:  20 bytes

    访问 https://任一节点ip:30010 端口,将 token 填写进行登录即可,页面如图所示:

    post-805-63afbac1bc981

    post-805-63afbac1ce92c

    7. 简单使用 dashboard

    登录面板以后,可以很方便的集群的各种资源如 pod、deployment、configmap 等进行查看。同时,提供了多种创建资源的方式。

    post-805-63afbac1ce92c

    接下来用表单创建一个 nginx 的 deploy。

    post-805-63afbac2e9a1d

    可以看见已经创建完成。

    post-805-63afbac3d741f

  • CloudFlare 开源证书管理工具 cfssl 详细使用教程

    CloudFlare 开源证书管理工具 cfssl 详细使用教程

    一、cfssl 是什么

    阿蛮君在看很多视频的时候都看见过 cfssl 这个工具,所有抽时间了解了下。

    在实际的工作中经常遇到制作自定义的服务器证书的场景,目前能够制作 CA 根证书及服务器证书有 openssl 及 cfssl 两种常用工具,之前介绍过 openssl 的 v3版 ssl 证书制作和 nginx 配置证书。

    下面了解一下 cfssl 和它的使用。

    cfssl 是 CloudFlare 开源的一款 PKI/TLS 工具。 cfssl 包含一个命令行工具 和一个用于签名,验证并且捆绑TLS证书的 HTTP API 服务。 使用Go语言编写。(目前常被用做 k8s 集群生成证书)

    64196d4b28c4e

    二、安装 cfssl

    1. 直接安装

    • 下载安装
    curl -s -L -o /usr/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 && \
    curl -s -L -o /usr/bin/cfssljson https://pkg.cfssl.org/R1.2/ cfssljson_linux-amd64 && \
    curl -s -L -o /usr/bin/cfssl-certinfo https://pkg.cfssl.org/R1.2/ cfssl-certinfo_linux-amd64 && \
    chmod +x /bin/cfssl*
    • 从 docker 容器拷贝
    cat > entrypoint.sh<<EOF
    #!/bin/sh
    tail -f /dev/null
    EOF
    chmod +x entrypoint.sh
    docker run -d --name cfssl -v $PWD:/workdir --entrypoint "/workdir/en.sh" cfssl/cfssl && \
    docker cp cfssl:/usr/bin/cfssl . && \
    docker cp cfssl:/usr/bin/cfssljson . && \
    docker cp cfssl:/usr/bin/cfssl-certinfo . && \
    mv cfssl* /usr/bin

    2. docker 安装

    docker pull cfssl/cfssl

    docker 安装方式与直接安装不同的是使用方式不同。

    cfssl/cfssl 镜像使用 /workdir 作为工作目录,为了使用方便可以使用宿主机当前目录映射到 /workdir。所以说需要的文件都应放在当前目录下,过程生成的文件也会输出在当前目录。

    例如:docker run --rm -v $PWD:/workdir cfssl/cfssl certinfo -cert ca.crt,ca.crt 证书文件需要放在当前目录下,否则提示没有这个文件。

    三、cfssl 命令

    使用 cfssl --help 可以看见 cfssl 工具的相关命令。

    version # 查看 cfssl 版本
    selfsign # 生成一个新的自签名密钥和签名证书
    certinfo # 输出给定证书的证书信息, 跟 cfssl-certinfo 工具作用一样
    print-defaults # 打印json格式的模板-ca签名配置文件和客户端证书请求文件
      # config:生成ca配置模板文件
      # csr:生成证书请求模板文件
    gencert # 生成新的key(密钥)和签名证书
      # -initca:初始化一个新ca (默认false,需要指定ca证书用以前面其他证书)
      # -ca:ca的证书
      # -ca-key:ca的私钥文件
      # -config:请求证书的json文件
      # -profile:与-config中的profile对应,是指根据config中的profile段来生成证书的相关信息
    sign # 签名一个客户端证书,通过给定的CA和CA密钥,和主机名
    revoke # 吊销证书
    info # 获取签名者信息
    bundle # 创建包含客户端证书的证书包
    serve # 启动一个HTTP API服务
    genkey  # 生成一个key(私钥)和csr(证书签名请求)
    gencsr # 生成新的证书请求文件
    gencrl # 生成新的证书吊销列表
    

    1. cfssl selfsign

    用于生成一个自签名证书,即自己颁发给自己的证书。

    提示自签名证书很危险,使用此自签名证书风险自负,强烈建议不要使用这些证书在生产中。

    # 1. 生成证书请求文件
    cat > server-csr.json<<EOF
    {
        "CN":"www.amjun.com",
        "hosts":[
            "127.0.0.1",
            "192.168.1.1",
            "amjun.com",
            "www.amjun.com"
        ],
        "key":{
            "algo":"rsa",
            "size":2048
        },
        "names":[
            {
                "OU":"iot",
                "O":"unipower",
                "ST":"GuangZhou",
                "L":"GuangDong",
                "C":"CN"
            }
        ]
    }
    EOF
    
    # 2. 生成私钥和证书
    # 使用方式 cfssl selfsign HOSTNAME CSRJSON
    cfssl selfsign www.amjun.com server-csr.json | cfssljson -bare  server
    # docker方式:
    docker run --rm -v $PWD:/workdir cfssl/cfssl selfsign www.amjun.com server-csr.json | cfssljson -bare server
    
    # 3. 查看证书
    cfssl certinfo -cert server.pem

    2. cfssl gencert

    使用证书请求文件生成证书。

    2.1 生成 CA 证书

    与自签名证书类似,生成 CA 证书也需要证书请求文件。

    # 1. 生成证书请求文件
    cat > ca-csr.json <<EOF
    {
        "CN":"kubernetes",
        "key":{
            "algo":"rsa",
            "size":2048
        },
        "names":[
            {
                "C":"CN",
                "L":"Hebei",
                "ST":"Zhangjiakou",
                "O":"k8s",
                "OU":"System"
            }
        ]
    }
    EOF
    
    # 2. 生成证书
    # -initca 指定这个生成 ca 证书,否则需要指定 ca 证书
    cfssl gencert -initca ca-csr.json | cfssljson -bare ca
    # docker方式:
    docker run --rm -v $PWD:/workdir cfssl/cfssl gencert -initca ca-csr.json | cfssljson -bare ca

    2.2 生成 CA 签名的证书

    # 1. 生成证书配置文件(CA 进行签名时需要的配置)
    cat > ca-config.json <<EOF
    {
        "signing":{
            "default":{
                "expiry":"87600h"
            },
            "profiles":{
                "kubernetes":{
                    "expiry":"87600h",
                    "usages":[
                        "signing",
                        "key encipherment",
                        "server auth",
                        "client auth"
                    ]
                }
            }
        }
    }
    EOF
    # 这个策略,有一个默认的配置,和一个profile,可以设置多个profile,这里的profile是etcd。
    # 默认策略,指定了证书的有效期是一年(8760h)
    # etcd策略,指定了证书的用途
    # signing, 表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE
    # server auth:表示 client 可以用该 CA 对 server 提供的证书进行验证
    # client auth:表示 server 可以用该 CA 对 client 提供的证书进行验证
    
    # 2. 生成服务端证书请求文件
    cat > server-csr.json <<EOF
    {
        "CN":"server",
        "hosts":[
            "127.0.0.1",
            "192.168.0.211",
            "192.168.0.212",
            "192.168.0.213",
            "10.10.10.1",
            "kubernetes",
            "kubernetes.default",
            "kubernetes.default.svc",
            "kubernetes.default.svc.cluster",
            "kubernetes.default.svc.cluste.local"
        ],
        "key":{
            "algo":"rsa",
            "size":2048
        },
        "names":[
            {
                "C":"CN",
                "L":"Hebei",
                "ST":"Zhangjiakou",
                "O":"k8s",
                "OU":"System"
            }
        ]
    }
    EOF
    
    # 3. 基于之前生成的ca证书生成证书
    cfssl gencert \
    -ca=ca.pem \
    -ca-key=ca-key.pem \
    -config=ca-config.json \
    -profile=kubernetes \
    server-csr.json | cfssljson -bare server
    # docker方式:
    docker run --rm -v $PWD:/workdir cfssl/cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server
    
    # 3. 查看证书
    cfssl certinfo -cert server.pem

    常用的就上面两个命令,基本满足日常使用

    下面讲讲其他的命令,有部分是前面的命令的其中一步。比如,下面cfssl genkey 就是只生成 key 文件和证书请求文件,并不会生成证书。

    3. cfssl genkey

    # 1. 生成证书配置文件
    cat > ca-config.json <<EOF
    {
        "signing":{
            "default":{
                "expiry":"87600h"
            },
            "profiles":{
                "kubernetes":{
                    "expiry":"87600h",
                    "usages":[
                        "signing",
                        "key encipherment",
                        "server auth",
                        "client auth"
                    ]
                }
            }
        }
    }
    EOF
    
    # 2. 生成密钥文件
    cfssl genkey ca-config.json | cfssljson -bare ca
  • Docker 搭建 etcd 单实例并使用图形界面进行访问

    Docker 搭建 etcd 单实例并使用图形界面进行访问

    一、etcd 了解

    阿蛮君最近在学习 k8s 相关的内容,了解到 etcd 是 k8s 一大重要的组件,所以来了解下相关的内容和使用。

    etcd 是一个分布式、可靠的键值存储,可用于分布式系统中存储关键核心数据。可以发现,etcd 归根结底是一个存储组件,且可以实现配置共享和服务发现。在分布式系统中,各种服务配置信息的管理共享和服务发现是一个很基本也是很重要的问题,无论调用服务还是调度容器,都需要知道对应的服务实例和容器节点地址信息。etcd 就是这样一款实现了元数据信息可靠存储的组件。

    etcd 可集中管理配置信息。服务端将配置信息存储于 etcd,客户端通过 etcd 得到服务配置信息,etcd 监听配置信息的改变,发现改变通知客户端。

    特性

    • 简单:etcd 的安装简单,且为用户提供了 HTTP API,使用起来也很简单。
    • 存储:etcd 的基本功能,数据分层存储在文件目录中,类似于我们日常使用的文件系统。
    • Watch 机制:Watch 指定的键、前缀目录的更改,并对更改时间进行通知。
    • 安全通信:支持 SSL 证书验证。
    • 高性能:etcd 单实例可以支持 2K/s 读操作,每个实例1000次写入/秒,官方也有提供基准测试脚本。
    • 一致可靠:基于 Raft 共识算法,实现分布式系统内部数据存储、服务调用的一致性和高可用性。

    使用场景

    • 键值对存储:etcd 是一个用于键值存储的组件,存储是 etcd 最基本的功能。
    • 消息发布与订阅:通过构建 etcd 消息中间件,服务提供者发布对应主题的消息,消费者则订阅他们关心的主题,一旦对应的主题有消息发布,就会产生订阅事件,消息中间件就会通知该主题所有的订阅者。
    • 分布式锁:分布式系统中涉及多个服务实例,存在跨进程之间资源调用,对于资源的协调分配,单体架构中的锁已经无法满足需要,需要引入分布式锁的概念。etcd 基于 Raft 算法,实现分布式集群的一致性,存储到 etcd 集群中的值必然是全局一致的,因此基于 etcd 很容易实现分布式锁。

    63f0680146f82.webp

    二、etcd 搭建

    1. server 搭建

    etcd 总归是提供 http 服务,etcdctl 工具也是通过 http 进行调用。

    # 1. 创建网卡,方便etcdctl进行访问
    docker network create etcd-net
    
    # 2. 启动etcd-server
    # 不需要验证
    docker run -d \
    --name etcd-server \
    --net etcd-net \
    -p 2379:2379 \
    -p 2380:2380 \
    -e ALLOW_NONE_AUTHENTICATION=yes \
    -e ETCD_ADVERTISE_CLIENT_URLS=http://etcd-server:2379 \
    bitnami/etcd
    
    # 需要root密码
    docker run -d \
    --name etcd-server \
    --net etcd-net \
    -p 2379:2379 \
    -p 2380:2380 \
    -e ETCD_ROOT_PASSWORD=123456 \
    -e ETCD_ADVERTISE_CLIENT_URLS=http://etcd-server:2379 \
    bitnami/etcd

    2. 客户端访问

    # 1. 查看成员列表-无需密码
    docker run -it --rm \
    --net etcd-net \
    -e ALLOW_NONE_AUTHENTICATION=yes \
    bitnami/etcd \
    etcdctl --endpoints http://etcd-server:2379 member list -w table
    
    # 2. 存储键值对
    docker run -it --rm \
    --net etcd-net \
    -e ALLOW_NONE_AUTHENTICATION=yes \
    bitnami/etcd \
    etcdctl --endpoints http://etcd-server:2379 put /message Hello
    # 带密码请求
    docker run -it --rm \
    --net etcd-net \
    -e ALLOW_NONE_AUTHENTICATION=yes \
    bitnami/etcd \
    etcdctl --endpoints http://etcd-server:2379 \
    --user="root" --password="123456" put /message Hello
    
    # 3. 获取键值对
    docker run -it --rm \
    --net etcd-net \
    -e ALLOW_NONE_AUTHENTICATION=yes \
    bitnami/etcd \
    etcdctl --endpoints http://etcd-server:2379 get /message
    # 带密码请求
    docker run -it --rm \
    --net etcd-net \
    -e ALLOW_NONE_AUTHENTICATION=yes \
    bitnami/etcd \
    etcdctl --endpoints http://etcd-server:2379 \
    --user="root" --password="123456" get /message

    三、etcd 可视化工具搭建

    docker run -d \
    --name=etcdui \
    --net etcd-net \
    -p 9980:80 \
    joinsunsoft/etcdv3-browser

    访问9980端口,用户名/密码:ginghan/123456。

    点击新增连接,如图所示:

    63f06817b291b.webp

    查询所有键,发现刚刚存储的键值对。

    63f0682666c43.webp

  • Docker 安装 minikube 学习 k8s

    Docker 安装 minikube 学习 k8s

    1. 安装minikube

    minikube 的安装非常简单,直接下载二进制文件即可。

    curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && \
    sudo install minikube-linux-amd64 /usr/local/bin/minikube

    2. 启动集群

    使用如下命令即可启动集群。

    minikube start
    # 默认不运行 root 运行,如果你非要用 root 用户运行的话,可以使用下面的命令
    # minikube start --force --driver=docker

    3. 配置

    3.1 设置别名

    如果没有安装 kubectl 命令,可以使用如下方法进行简化操作。

    cat >> ~/.bashrc <<EOF
    alias kubectl="minikube kubectl --"
    EOF

    重新加载环境变量

    source ~/.bashrc

    3.1 安装dashboard面板

    后台运行面板:

    minikube dashboard &

    此时面板已经后台运行,不过只能本机访问,如果需要开启其他机器访问,还需要执行:

    minikube kubectl -- proxy --port=8900 --address='0.0.0.0' --accept-hosts='^.*'

    然后访问 http://ip:8900/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ 即可。

    4. 简单使用

    查看所有的 pod,其他的命令也是类似。

    kubectl get pod -A

    644a4835196ae

    5. 相关命令

    5.1. 启动 Minikube

    minikube start

    该命令用于启动 Minikube 并创建一个新的 Kubernetes 集群,它会自动安装所需的 Kubernetes 组件。

    5.2. 停止 Minikube

    minikube stop

    该命令用于停止 Minikube。

    5.3. 删除 Minikube

    minikube delete

    该命令用于删除 Minikube。在执行此命令后,Minikube 和所有相关资源将被删除。

    5.4 查看 Minikube 的状态

    minikube status

    用于查看 Minikube 的状态,显示当前运行的 Kubernetes 版本、Minikube 的 IP 地址和状态。

    5.5 连接到 Minikube 集群

    minikube ssh

    该命令用于连接到 Minikube 集群。它会在新的终端窗口中打开一个 SSH 连接,可以在里面执行命令。

    5.6 打开 Kubernetes 仪表板

    minikube dashboard

    该命令用于打开 Kubernetes 仪表板。

    5.7 显示 Minikube IP

    minikube ip

    该命令用于显示 Minikube 的 IP 地址,这对于连接到 Kubernetes 集群并在本地测试应用程序非常有用。

    5.8 显示 Minikube 版本

    minikube version
  • 6月25日,星期日,在这里每天60秒读懂世界!

    6月25日,农历五月初八,星期日!

    在这里,每天60秒读懂世界!

    1、文旅部:2023年端午节假期,全国国内旅游出游1.06亿人次,同比增长32.3%,实现国内旅游收入373.10亿元;

    2、24日凌晨,广西北部湾发生5.0级地震,震源深度20公里,全省多市震感明显,暂未收到人员伤亡报告;

    6月24日凌晨,我国北部湾发生5.0级地震。目前,距震中位较近的北海、海口等地未发现人员伤亡及建筑倒塌等情况。

    3、23日下午,浙江龙游发生5车追尾事故,并引发燃烧,已造成6死2伤;24日晚,甘肃兰州西固区一企业发生闪爆事故,网友:事故现场为一座装置起火闪爆,并冒起浓烟,目前伤亡情况不详;

    https://www.zhihu.com/video/1656098797011894272

    4、银川31死爆炸事故原因公布:两人擅自更换与液化气罐相连接的减压阀,导致液化气罐中液化气快速泄漏,引发爆炸;

    经查,烧烤店总店长海某(已死亡)、工作人员李某翔(已死亡)违反有关安全管理规定,擅自更换与液化气罐相连接的减压阀,导致液化气罐中液化气快速泄漏,引发爆炸,造成31人死亡、7人受伤的特别严重后果。

    5、手机QQ支持微信登录了:QQ和微信实现账号互通;

    6、24日凌晨,香港一客机中止起飞致11名乘客受伤,国泰航空:技术故障,将配合调查;

    https://www.zhihu.com/video/1656099448072601600

    7、台媒:台湾竹北市24日发生多起瓦斯外泄和气爆事件,多名居民被炸伤;

    6月24日,台湾竹北市发生瓦斯漏气及火警案件。 图自台湾中时新闻网

    8、美方以涉芬太尼问题逮捕和起诉中国公民和企业,外交部:美方诱捕中国公民,并悍然再次起诉中国实体和个人,中方对此予以强烈谴责,已提出严正交涉和强烈抗议;

    美国芬太尼滥用严重,图自路透社

    9、外媒:传荷兰最早下周发布新出口管制措施,限制ASML对华半导体设备出口;

    10、外媒:马斯克的SpaceX将出售内部股票,公司估值增至1500亿美元;

    11、泰国和美国两地大量鱼类死亡,专家:或与海洋异常升温有关;

    12、"瓦格纳"领导人普里戈任称:俄军袭击瓦格纳营地,俄军否认称:其因号召武装叛乱被立案。外媒:"瓦格纳"已占领俄南部军区指挥部,"正在穿越"利佩茨克州往莫斯科方向,俄军正在莫斯科市郊挖战壕,架设机枪阵地,莫斯科及沃罗涅日已进入反恐状态;

    13、普京指责普里戈任"叛国"。普里戈任:不是叛国,目的是将俄从腐败中解救;卡德罗夫:完全支持普京,车臣士兵已前往;俄警方在他办公室搜出40亿卢布现金,普里戈任:发工资和抚恤金的钱;

    14、普京签署法律:允许戒严期间征召有犯罪记录公民入伍;俄国防部:乌克兰军队试图利用"瓦格纳"部队挑衅的机会发动反攻;普里戈任喊话国防部长:来见我;

    15、美媒:白宫官员称,美方正关注俄国内局势,拜登已听取相关简报;欧盟:"瓦格纳"事件属于俄内政,正密切关注;土媒:埃尔多安告诉普京,土方准备为尽快和平解决俄国内所发生事件出力;

    【微语】不要等错过了才悔恨,不要等老了才怀念。抓住当下,再苦再累也要展翅飞翔。