kubernets集群部署

kubernets集群部署流程:

  • 网络、主机等规划
    • 规划集群网络
    • 规划主机集群架构(如节点多机房灾备等)
  • 主机系统初始化
    • 主机名
    • 软件源
    • 关闭swap
    • 关闭防火墙
    • 关闭selinux
    • 配置chrony
    • 安装依赖软件包
    • 加载相关内核模块
    • 内核优化
    • 配置数据盘
  • 签发集群证书
    • 签发ca证书
    • 签发etcd证书
    • 签发admin证书
    • 签发apiserver证书
    • 签发metrics-server证书
    • 签发controller-manager证书
    • 签发scheduler证书
    • 签发kube-proxy证书
  • 部署etcd高可用集群
    • etcd集群部署
    • etcd数据备份
  • apiserver的高可用配置
    • haproxy+keepalived
  • 部署master节点
    • 生成kuberctl kubeconfig,配置kubectl
    • 安装配置kube-apiserver
    • 安装配置kube-controller-mannager
    • 安装配置kube-scheduler
  • 部署node节点
    • 安装配置docker
    • 安装配置kubelet
    • 安装配置kube-proxy
  • 部署calico

kubernetes集群部署要点:

  • 关闭非安全端口,通过–anonymous-auth=false关闭匿名请求,所有通信使用证书认证,防止请求被篡改;通过证书认证和授权策略(x509、token、RBAC)。
  • 开启bootstrap token认证,动态创建token,而不是在apiserver中静态配置。
  • 使用TLS bootstrap机制自动生成kubelet client和server证书,过期自动轮转(部分集群部署使用admin证书签发kubelet.kubeconfig,这样集群非常不安全)。
  • etcd、master证书指定节点IP,限制访问,即便某个节点证书泄漏,在其他机器上也无法使用。
  • 网络使用calico ipip

我已经将kubernetes集群安装过程写成ansible-playbook,实现一键部署、扩容kubernets高可用集群(https://github.com/k8sre/k8s_init.git)。playbook包含了系统初始化、签发证书、部署etcd、部署k8s、替换集群证书等。

我们Devops平台对接了Ansible Playbook,可在DevOps平台上操作部署、扩容,配合工单系统,完成全自动化流程。

DevOps平台操作部署、扩容kubernets集群流程:

  • 填写申请机器工单
  • 选择用途为kubernetes新建或者扩容
  • 选择对应角色
  • 工单审批通过后,自动申请机器
  • 调用Ansible Playbook开始进行系统初始化
  • 调用Ansible Playbook开始进行证书签发
  • 调用Ansible Playbook开始进行etcd集群部署
  • 调用Ansible Playbook开始进行节点扩容

同时也可以使用以下命令进行操作:

通过以下命令即可将一批刚刚安装好系统、配置好网络的机器部署为一套生产可用的k8s集群:

ansible-playbook k8s.yml -i inventory

扩容master节点

ansible-playbook k8s.yml -i inventory -t init -l master
ansible-playbook k8s.yml -i inventory -t cert,install_master 

扩容node节点

ansible-playbook k8s.yml -i inventory -t init -l node
ansible-playbook k8s.yml -i inventory -t cert,install_node

通过本playbook部署集群,可以在很短的时间内完成集群扩容。生产上使用本Playbook最高一次性扩容过50个node节点。

因为时间关系,这里先简单介绍下kubelet TLS Bootstrapping和etcd的自动备份,其他部分就不再进一步讲解,具体详细部署大家可参考(https://github.com/k8sre/docs/blob/master/kubernetes/kubernetes高可用集群之二进制部署.md)

Kubelet TLS Bootstrapping

在Kubernetes集群中,工作节点上的组件(kubelet和kube-proxy)需要与Kubernetes主组件通信,特别是kube-apiserver。为了确保通信保持私密,不受干扰,并确保群集的每个组件与另一个受信任组件通信,我们强烈建议在节点上使用客户端TLS证书。

引导这些组件的正常过程,特别是需要证书的工作节点,因此它们可以与kube-apiserver安全地通信,这可能是一个具有挑战性的过程,因为它通常超出了Kubernetes的范围,需要大量的额外工作。反过来,这可能会使初始化或扩展集群变得具有挑战性。

为了简化流程,从版本1.4开始,Kubernetes引入了证书请求和签名API以简化流程。

kubernetes开启TLS认证后,每个node节点的kubelet都要使用由kube-apiserver的ca签发证书,才能与kube-apiserver进行通信,如果接入比较多的节点,为每个节点生成证书不太现实,Bootstrapping就是让kubelet先使用一个低权限用户连接到kube-apiserver,然后由kube-controller-manager为kubelet动态签发证书。再配合RBAC指定用户拥有访问哪些API的权限。

CSR 请求

kubelet启动后会发起CSR请求,kube-apiserver 收到 CSR 请求后,对其中的 Token 进行认证,认证通过后将请求的 user 设置为 system:bootstrap:<Token ID>,group 设置为 system:bootstrappers,这一过程称为 Bootstrap Token Auth。

kubelet发起的 CSR 请求都是由kube-controller-manager来做实际签发的,对于kube-controller-manager来说,TLS bootstrapping 下 kubelet 发起的 CSR 请求大致分为以下三种

  • nodeclient: kubelet 以 O=system:nodesCN=system:node:(node name) 形式发起的 CSR 请求
  • selfnodeclient: kubelet client renew 自己的证书发起的 CSR 请求(与上一个证书就有相同的 O 和 CN)
  • selfnodeserver: kubelet server renew 自己的证书发起的 CSR 请求

使用 Bootstrap Token 时整个启动引导过程:

  • 配置apiserver使用 Bootstrap Token Secret,替换以前使用token.csv文件
  • 在集群内创建首次 TLS Bootstrap 申请证书的 ClusterRole、后续 renew Kubelet client/server 的 ClusterRole,以及其相关对应的 ClusterRoleBinding;并绑定到对应的组或用户
  • 配置controller-manager,使其可以自动签发相关证书和自动清理过期的TLS Bootstrapping Token
  • 生成特定的包含 TLS Bootstrapping Token 的 bootstrap.kubeconfig 以供 kubelet 启动时使用
  • 配置kubelet,使其首次启动加载 bootstrap.kubeconfig 并使用其中的 TLS Bootstrapping Token 完成首次证书申请
  • controller-manager签发证书,并生成kubelet.kubeconfig,kubelet自动重载完成引导流程
  • 后续 kubelet 自动 renew 相关证书
  • 集群搭建成功后立即清除 Bootstrap Token Secret ,或等待 Controller Manager 待其过期后删除,以防止被恶意利用

下面讲一下etcd备份

ETCD备份

Etcd是Kubernetes集群中的一个十分重要的组件,用于保存集群所有的网络配置和对象的状态信息。一旦出现问题或者数据丢失,影响将无法估计。所以,我们一定要做好etcd的数据备份。

这里利用kubernetes的cronjob对etcd进行备份,并挂载外部存储,将数据备份在外部存储上。

以下是使用cronjob备份的yaml

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: etcd-backup
spec:
  schedule: "10 1 * * *"
  concurrencyPolicy: Allow
  failedJobsHistoryLimit: 3
  successfulJobsHistoryLimit: 3
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: etcd-backup
            imagePullPolicy: IfNotPresent
            image: k8sre/etcd:v3.3.15
            env:
            - name: ENDPOINTS
              value: "https://172.16.70.131:2379,https://172.16.70.132:2379,https://172.16.70.133:2379"
            command:
            - /bin/bash
            - -c
            - |
              set -ex
              ETCDCTL_API=3 /opt/etcd/etcdctl \
                --endpoints=$ENDPOINTS \
                --cacert=/certs/ca.pem \
                --cert=/certs/etcd.pem \
                --key=/certs/etcd.key \
                snapshot save /data/backup/snapshot-$(date +"%Y%m%d").db
            volumeMounts:
            - name: etcd-backup
              mountPath: /data/backup
            - name: etcd-certs
              mountPath: /certs
          restartPolicy: OnFailure
          volumes:
          - name: etcd-backup
            persistentVolumeClaim:
              claimName: etcd-backup
          - name: etcd-certs
            secret:
              secretName: etcd-certs

下面来讲一下,我们的CICD是如何实现的。

先给大家看下我们大概的架构图:
在这里插入图片描述
我们业务主要的开发语言包含Java、PHP、Golang、NodeJs以及少部分Python,涉及开发语言较广,CI、CD需求各种各样等原因,我们选择使用Jenkins Pipeline来完成CI、CD的相关工作,全部逻辑通过Groovy语言编写。并通过Jenkins Agent的方式适配公司所有开发语言代码的CICD。同时支持虚拟机和k8s部署。

Jenkins Master及所有agent都部署在kubernetes集群,并使用pvc挂载一块极速nas作为数据同步。下面给大家看下我们部分部署yaml:
jenkins-master.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-master
  namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: jenkins-master
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: jenkins-master
  namespace: jenkins

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: jenkins-master
  namespace: jenkins
spec:
  serviceName: "jenkins-master"
  replicas: 1
  selector:
    matchLabels:
      app: jenkins-master
  template:
    metadata:
      labels:
        app: jenkins-master
    spec:
      serviceAccount: jenkins-master
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: app
                operator: In
                values:
                - jenkins
      containers:
      - name: jenkins
        image: k8sre/jenkins:master
        imagePullPolicy: Always
        securityContext:
          runAsUser: 0
          privileged: true
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        - containerPort: 50000
          name: agentport
          protocol: TCP
        resources:
          limits:
            cpu: 2
            memory: 4Gi
          requests:
            cpu: 2
            memory: 4Gi
        livenessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 10
          timeoutSeconds: 3
          periodSeconds: 5
        readinessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 10
          timeoutSeconds: 3
          periodSeconds: 5
        volumeMounts:
        - name: jenkins-data
          mountPath: /data/jenkins
        - name: sshkey
          mountPath: /root/.ssh/id_rsa
          subPath: id_rsa
          readOnly: true
        - name: jenkins-docker
          mountPath: /var/run/docker.sock
        - name: jenkins-maven
          mountPath: /usr/share/java/maven-3/conf/settings.xml
          subPath: settings.xml
          readOnly: true
      volumes:
        - name: sshkey
          configMap:
            defaultMode: 0600
            name: sshkey
        - name: jenkins-docker
          hostPath:
            path: /var/run/docker.sock
            type: Socket
        - name: jenkins-maven
          configMap:
            name: jenkins-maven
        - name: jenkins-data
          persistentVolumeClaim:
            claimName: jenkins
---
apiVersion: v1
kind: Service
metadata:
  name: jenkins-master
  namespace: jenkins
spec:
  ports:
  - name: web
    port: 8080
    protocol: TCP
    targetPort: 8080
  - name: agent
    port: 50000
    protocol: TCP
    targetPort: 50000
  selector:
    app: jenkins-master

agent-go.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: agent-go
  namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: agent-go
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: agent-go
  namespace: jenkins

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: agent-go
  namespace: jenkins
spec:
  serviceName: "agent-go"
  replicas: 1
  selector:
    matchLabels:
      app: agent-go
  template:
    metadata:
      labels:
        app: agent-go
    spec:
      serviceAccount: agent-go
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: role
                operator: In
                values:
                - jenkins
      containers:
      - name: jenkins
        image: k8sre/jenkins:go
        imagePullPolicy: Always
        securityContext:
          runAsUser: 600
          privileged: true
        env:
        - name: "ENV_NAME"
          value: "go"
        - name: "JKS_SECRET"
          value: "xxxxxxxxxxxxxx"
        - name: "JKS_DOMAINNAME"
          value: "https://ci.k8sre.com"
        - name: "JKS_ARGS"
          value: "-Xmx4g -Xms4g"
        - name: "JKS_DIR"
          value: "/data/jenkins"
        volumeMounts:
        - mountPath: /data/jenkins
          name: jenkins-data
      volumes:
        - name: jenkins-data
          persistentVolumeClaim:
            claimName: jenkins

下图是我们目前jenkins在使用的节点:
在这里插入图片描述
以下是CICD的流程图:
我们CICD的流程:

  • —> 在DevOps平台创建项目(Devops平台提供项目管理、配置管理、JOB处理、日志查看、监控信息、k8s容器web terminal等管理功能,CICD后续流程全部为Jenkins处理)
  • —>选择是容器部署or虚机部署
  • —>按照提示填写相关配置(包含开发语言、GIT仓库、编译命令、域名、容器内可写目录、运行命令、运行端口、资源限制、健康检查等)
  • —>保存配置
  • —>触发JOB
  • —>发布前检查/拉取项目配置(同时对项目配置进行校验是否符合规范)
  • —>拉取业务代码
  • —>漏洞扫描
  • —>编译构建
  • —>根据配置选择对应语言的编译节点
  • —>判断虚机还是容器部署,选择不同的部署流程
  • —> 容器部署会根据项目配置生成Dockerfile并构建上传镜像(适配所有业务Dockerfile自动生成,并支持自定义)
  • —>选择环境(prd or pre or qa or dev )
  • —>helm使用模版替换项目配置进行部署(helm chart模版适配了所有业务需求,并支持自定义。默认部署deployment、service、ingress、hpa)
  • —>部署结束后发送部署详情通知

在这里插入图片描述
jenkins pipeline测试环境阶段视图示例:
在这里插入图片描述
更多技术文章请关注公众号:架构师Plus,
扫码添加
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值