2024-08-10



# 在Kubernetes集群中部署Jenkins主服务器
 
# 创建Jenkins主服务器的Docker Registry凭证
kubectl create secret docker-registry jenkins-docker-credentials \
  --docker-server=<DOCKER_REGISTRY_SERVER> \
  --docker-username=<DOCKER_USER> \
  --docker-password=<DOCKER_PASSWORD> \
  --docker-email=<DOCKER_EMAIL>
 
# 创建Jenkins持久化存储的StorageClass
kubectl apply -f jenkins-storageclass.yaml
 
# 创建Jenkins主服务器的配置文件
kubectl create configmap jenkins-config --from-file=jenkins.yaml
 
# 部署Jenkins主服务器
kubectl apply -f jenkins-deployment.yaml
 
# 暴露Jenkins服务,以便于从外部访问
kubectl apply -f jenkins-service.yaml

在这个例子中,我们首先创建了一个Docker Registry凭证,用于拉取Jenkins镜像。然后,我们创建了一个StorageClass资源,以便动态地为Jenkins提供持久化存储。接着,我们创建了一个ConfigMap,用于存储Jenkins的配置文件。最后,我们应用了Jenkins的Deployment和Service资源,以便在Kubernetes集群上部署和暴露Jenkins服务。

2024-08-10

PM2 和 Kubernetes 是两种不同的工具,它们用于不同的目的,并且在不同的场景下有各自的优势。

PM2 是一个进程管理工具,可以用来保持应用程序的活跃状态,管理重启,日志记录等。它适用于单个节点的部署,适合管理 Node.js 应用程序的生命周期。

Kubernetes 是一个开源的容器编排平台,用于自动部署,扩展和管理容器化的应用程序。Kubernetes 提供了服务发现,负载均衡,自动扩缩容等高级功能。

Node.js 服务部署比较:

如果你的服务需要单个节点部署,并需要进程管理,自动重启等功能,那么使用 PM2 是一个不错的选择。

如果你的服务需要跨多个节点部署,并且需要自动扩缩容,金丝管理,服务发现等高级功能,那么 Kubernetes 是更好的选择。

使用 PM2 部署 Node.js 服务:

安装 PM2:




npm install pm2 -g

启动你的 Node.js 应用:




pm2 start app.js

使用 Kubernetes 部署 Node.js 服务:

创建一个 Dockerfile:




FROM node:14
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD ["node", "app.js"]

构建 Docker 镜像:




docker build -t my-node-app .

在 Kubernetes 集群中部署你的 Node.js 应用: \`\`\`yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-node-app spec: selector: matchLabels: app: my-node-app strategy: type: RollingUpdate template: metadata: labels: app: my-node-app spec: containers: - name: my-node-app image: my-node-app ports: - containerPort: 8080

apiVersion: v1

kind: Service

metadata:

name: my-node-app-service

spec:

selector:

app: my-node-app

ports:

- protocol: TCP

port: 80

targetPort: 8080

type: LoadBalancer




 
应用这个配置文件来创建 Kubernetes 部署:
```bash
kubectl apply -f my-node-app.yaml

以上是使用 PM2 和 Kubernetes 部署 Node.js 服务的基本方法。在实际部署时,你可能需要根据具体的需求和环境来调整配置。

2024-08-09

要在Kubernetes Pod中连接到外部MySQL服务,您可以使用外部服务的IP地址或主机名创建一个ServiceEntry资源。以下是一个示例ServiceEntry资源的YAML配置,它允许Pods访问外部MySQL服务:




apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: mysql-external-service
spec:
  hosts:
  - my-external-mysql.example.com # 替换为外部MySQL服务的主机名或IP
  ports:
  - number: 3306                 # MySQL的默认端口
    name: mysql
    protocol: TCP
  location: MESH_EXTERNAL
  resolution: DNS

保存这个文件为mysql-external-service.yaml,然后使用kubectl命令应用它:




kubectl apply -f mysql-external-service.yaml

在您的Kubernetes集群中的Pods现在可以通过主机名my-external-mysql.example.com连接到外部MySQL服务了。确保将主机名替换为外部MySQL服务的实际主机名或IP地址。

注意:这里使用了Istio的ServiceEntry资源,这意味着您需要在集群中安装和使用Istio服务网格。如果您没有使用Istio,则需要找到对应的Kubernetes方式来添加外部服务。




apiVersion: v1
kind: ConfigMap
metadata:
  name: metribeat-config
  namespace: kube-system
data:
  metribeat.yml: |-
    metricbeat.config.modules:
      path: ${path.config}/modules.d/*.yml
      reload.enabled: false

    setup.kibana:
      host: "kibana.kube-system.svc:5601"
 
    output.elasticsearch:
      hosts: ["http://elasticsearch.monitoring.svc:9200"]
      username: "elastic"
      password: "changeme"
 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: metribeat
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: metribeat
  template:
    metadata:
      labels:
        k8s-app: metribeat
    spec:
      serviceAccountName: metribeat
      containers:
      - name: metribeat
        image: docker.elastic.co/beats/metribeat:7.10.0
        args: [
          "-c", "/usr/share/metribeat/config/metribeat.yml",
          "-e",
          "-d", "publish"
        ]
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 100Mi
        volumeMounts:
        - name: config
          mountPath: /usr/share/metribeat/config
        - name: elastic-ca-certs
          mountPath: /usr/share/metribeat/config/elastic-stack-ca.crt
          readOnly: true
 
      volumes:
      - name: config
        configMap:
          name: metribeat-config
          items:
          - key: metribeat.yml
            path: metribeat.yml
      - name: elastic-ca-certs
        configMap:
          name: elastic-stack-ca
          items:
          - key: elastic-stack-ca.crt
            path: elastic-stack-ca.crt
 
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: metribeat
  namespace: kube-system
 
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: metribeat-read-es-binding
subjects:
- kind: ServiceAccount
  name: metribeat
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name:

以下是一个简化的例子,展示如何使用Docker Compose来快速部署一个简单的EFK系统。

  1. 创建一个名为 docker-compose.yml 的文件,内容如下:



version: '3'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.0
    environment:
      - discovery.type=single-node
    volumes:
      - esdata1:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    networks:
      - efk-net
 
  kibana:
    image: docker.elastic.co/kibana/kibana:7.10.0
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - efk-net
 
  filebeat:
    image: docker.elastic.co/beats/filebeat:7.10.0
    volumes:
      - /var/lib/docker/containers:/var/lib/docker/containers
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - ELASTICSEARCH_HOST=elasticsearch
    networks:
      - efk-net
 
volumes:
  esdata1:
    driver: local
 
networks:
  efk-net:
    driver: bridge
  1. 在包含该 docker-compose.yml 文件的目录中运行以下命令来启动服务:



docker-compose up -d

这将启动一个包含Elasticsearch、Kibana和Filebeat的EFK系统。Elasticsearch用于索引和搜索日志,Kibana用于日志的可视化,Filebeat用于收集容器日志。

请注意,这个例子是为了演示目的而简化的。在生产环境中,你需要对Elasticsearch进行更多的配置,比如设置密码、配置持久化存储、扩展集群等。

2024-08-08

'# KubeSphere核心实战:使用KubeSphere给Kubernetes部署中间件

一、背景与问题

在云原生架构中,中间件作为系统的核心组件,其部署和管理复杂度远超普通应用。传统Kubernetes部署需要处理存储卷配置、服务发现、网络策略、安全策略等多个维度,而KubeSphere作为Kubernetes的增强平台,通过可视化界面和自动化能力显著降低了部署门槛。本文将深入解析KubeSphere部署中间件的底层原理,结合MySQL数据库的完整部署案例,探讨其在分布式云原生架构中的适用场景与技术细节。

二、基本原理

KubeSphere通过以下核心机制实现中间件部署:

  1. 多租户隔离:基于RBAC和命名空间的隔离机制
  2. 存储抽象层:通过StorageClass抽象不同存储后端
  3. 服务网格:基于Service和Ingress的流量管理
  4. 状态管理:持久化存储的配置管理
  5. 安全策略:基于NetworkPolicy的网络隔离

在Kubernetes中,中间件部署需要解决三个核心问题:

  • 存储持久化(PersistentVolume/PVC)
  • 服务发现(Service/Ingress)
  • 网络策略(NetworkPolicy)

三、环境准备

  1. KubeSphere环境

    # 安装KubeSphere
    kubectl apply -f https://raw.githubusercontent.com/kubesphere/kubesphere/main/installer/local.yaml
  2. 存储配置

    # storageclass.yaml
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: managed-nfs-storage
    provisioner: kubernetes-sigs/nfs
    parameters:
      server: nfs-server.example.com
      path: /exports
    reclaimPolicy: Retain
    mountOptions:
      - vers=3
  3. 网络策略

    # networkpolicy.yaml
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: mysql-network
    spec:
      podSelector:
        matchLabels:
          app: mysql
      policyTypes:
        - Ingress
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              app: database

四、核心实现

1. 中间件部署流程

KubeSphere部署中间件的典型流程包括:

  1. 创建命名空间
  2. 配置存储卷
  3. 部署工作负载
  4. 配置服务发现
  5. 设置应用路由

2. MySQL部署示例

# mysql-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  namespace: database
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "rootpass"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-data
        persistentVolumeClaim:
          claimName: mysql-pvc
# mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: database
spec:
  selector:
    app: mysql
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306
# mysql-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: mysql-ingress
  namespace: database
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /mysql
        pathType: Prefix
        backend:
          service:
            name: mysql
            port:
              number: 3306

3. 关键代码解析

1. 存储卷配置

volumeMounts:
- name: mysql-data
  mountPath: /var/lib/mysql
  • mountPath指定容器内的挂载路径
  • PVC会自动绑定到StorageClass定义的存储后端
  • 需要确保StorageClass配置正确(见上文)

2. 服务发现配置

selector:
  app: mysql
  • 标签选择器确保服务能发现同标签的Pod
  • 必须与Deployment的标签匹配

3. 网络策略

ingress:
- from:
  - namespaceSelector:
      matchLabels:
        app: database
  • 限制只有database命名空间的Pod可以访问
  • 防止跨命名空间的未授权访问

五、完整案例

案例:部署MySQL数据库集群

  1. 创建命名空间

    kubectl create namespace database
  2. 创建StorageClass

    kubectl apply -f storageclass.yaml
  3. 创建PVC

    # pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mysql-pvc
      namespace: database
    spec:
      accessModes:
        - ReadWriteOnce
      storageClassName: managed-nfs-storage
      resources:
        requests:
          storage: 1Gi
  4. 部署MySQL

    kubectl apply -f mysql-deployment.yaml
    kubectl apply -f mysql-service.yaml
    kubectl apply -f mysql-ingress.yaml
  5. 验证部署

    kubectl get pods -n database
    kubectl get svc -n database
    kubectl get ingress -n database
  6. 应用路由配置

    # ingress-rewrite.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: mysql-ingress
      namespace: database
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /$1
        nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
    spec:
      rules:
      - http:
          paths:
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: mysql
                port:
                  number: 3306

六、源码解析

  1. Deployment源码结构

    • spec.replicas控制副本数
    • spec.selector与template.metadata.labels必须匹配
    • volumeMounts和volumes定义存储配置
  2. Service源码解析

    • spec.selector必须与Deployment的标签匹配
    • spec.ports定义服务端口映射
    • spec.clusterIP可设置为None实现Headless Service
  3. Ingress源码分析

    • spec.rules定义路由规则
    • annotations配置反向代理参数
    • spec.tls配置HTTPS证书

七、进阶使用

  1. 多副本部署

    spec:
      replicas: 3
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxUnavailable: 1
  2. 自动扩展

    spec:
      autoscaling:
        minReplicas: 2
        maxReplicas: 5
        targetCPUUtilizationPercentage: 80
  3. 高级安全配置

    spec:
      containers:
      - name: mysql
        securityContext:
          runAsUser: 1000
          runAsGroup: 1000
          fsGroup: 1000
  4. 网络策略优化

    spec:
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              app: database
        - ipBlock:
            cidr: 192.168.0.0/24

八、性能与工程实践

1. 性能优化

  • 存储性能调优

    spec:
      storageClassName: ssd-storage
      resources:
        requests:
          storage: 10Gi
    • 选择高性能存储类
    • 避免小块存储分配
  • 服务发现优化

    spec:
      selector:
        app: mysql
      ports:
      - protocol: TCP
        port: 3306
        targetPort: 3306
        name: mysql
    • 精确匹配标签
    • 使用服务别名提高可读性
  • 应用路由优化

    spec:
      rules:
      - http:
          paths:
          - path: /mysql
            pathType: Prefix
            backend:
              service:
                name: mysql
                port:
                  number: 3306
    • 使用路径匹配避免正则复杂度
    • 避免过度使用正则表达式

2. 安全实践

  • TLS加密

    spec:
      tls:
      - hosts:
        - "mysql.example.com"
        secretName: mysql-tls
  • 访问控制

    spec:
      rules:
      - http:
          paths:
          - path: /mysql
            pathType: Prefix
            backend:
              service:
                name: mysql
                port:
                  number: 3306
              # 添加安全策略
  • 网络隔离

    spec:
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              app: database
        - ipBlock:
            cidr: 192.168.0.0/24

九、常见问题与踩坑

1. 常见错误及解决

错误1:存储卷无法挂载

Error: failed to create PVC: Storage class not found
  • 原因:未正确配置StorageClass
  • 解决:检查storageclass.yaml配置

错误2:服务无法访问

Error: No endpoints found for service mysql
  • 原因:Deployment标签未匹配
  • 解决:检查Deployment的标签与Service的selector

错误3:网络策略限制访问

Error: Connection refused
  • 原因:网络策略限制了访问
  • 解决:检查NetworkPolicy的from配置

2. 常见坑点

  • 存储类配置错误:未正确配置StorageClass导致PVC创建失败
  • 标签不匹配:Deployment的标签与Service的selector不一致
  • 网络策略过严:未正确配置允许访问的源地址
  • 证书过期:TLS证书未及时更新导致HTTPS连接失败
  • 资源不足:未合理分配CPU/Memory资源导致服务异常

十、最佳实践

  1. 命名空间隔离:使用命名空间区分不同业务系统
  2. 存储类优化:根据业务需求选择合适的存储后端
  3. 服务发现规范:统一使用Service/Ingress进行服务暴露
  4. 安全策略:启用TLS加密和RBAC访问控制
  5. 监控告警:集成Prometheus/Grafana进行监控
  6. 滚动更新:配置RollingUpdate策略保证服务可用
  7. 备份恢复:定期备份PVC数据并测试恢复流程

十一、总结

KubeSphere通过其完善的云原生特性,为中间件部署提供了完整的解决方案。在分布式云原生架构中,其多租户隔离、存储抽象、服务发现和网络策略等核心能力,显著降低了部署复杂度。本文通过MySQL数据库的完整部署案例,深入解析了KubeSphere的底层原理,探讨了其在实际项目中的应用场景和注意事项。建议在需要高可用、自动扩展、多租户隔离的场景中使用该方案,而在单机环境或简单应用部署中应谨慎使用。通过合理配置存储类、服务发现和安全策略,可以充分发挥KubeSphere在云原生架构中的优势。

2024-08-07

Linux 无残留卸载 k8s

一、背景与问题

在 Kubernetes(k8s)部署过程中,由于其依赖的组件复杂、配置文件多、系统资源占用高,卸载时常常会残留大量文件和配置。这些残留物可能包括:

  • 服务进程(kubelet、kube-proxy 等)
  • 配置文件(/etc/kubernetes/ 目录)
  • 证书文件(/etc/ssl/ 或 /etc/kubelet/)
  • 网络插件配置(Calico、Flannel 等)
  • 系统规则(iptables、cgroup 等)

若未彻底清理,可能导致:

  1. 系统资源占用异常(如内存泄漏)
  2. 新部署的 k8s 环境配置异常
  3. 安全风险(残留证书可能被用于非法用途)
  4. 调试困难(残留日志、状态文件)

本文将深入分析 k8s 卸载原理,提供完整的无残留卸载方案,并结合真实开发场景讨论适用范围和注意事项。


二、基本原理

1. k8s 组件结构

k8s 在 Linux 上运行时,主要包含以下核心组件:

组件作用安装方式
kubelet节点代理,负责容器生命周期管理二进制安装/包管理
kube-proxy网络策略代理二进制安装/包管理
kubectl命令行工具二进制安装
kube-apiserver核心 API 服务二进制安装
etcd分布式键值存储二进制安装
CNI 网络插件网络配置第三方安装

2. 卸载关键点

  • 服务进程:需通过 systemctl stop 或 kill 终止
  • 配置文件:需删除 /etc/kubernetes/ 和 /var/lib/kubelet/ 等目录
  • 证书文件:需清理 /etc/ssl/ 或 /etc/kubelet/ 目录
  • 网络规则:需清理 iptables 或 nftables 规则
  • 系统配置:需恢复默认的 cgroup 和 SELinux 等设置

三、环境准备

1. 系统要求

  • Linux 发行版:CentOS 7/Ubuntu 18.04+(支持 kubeadm)
  • 内存:≥ 4GB
  • 磁盘空间:≥ 10GB(用于临时卸载过程)

2. 工具准备

# 安装依赖工具
sudo apt install -y curl jq

3. 额外配置(仅在使用 kubeadm 时)

# 禁用 swap(kubeadm 需要)
sudo swapoff -a

四、核心实现

1. 通用卸载流程(基于 kubeadm 安装)

# 停止服务
sudo systemctl stop kubelet kube-proxy
sudo systemctl disable kubelet kube-proxy

# 删除配置文件
sudo rm -rf /etc/kubernetes/
sudo rm -rf /var/lib/kubelet/
sudo rm -rf /etc/ssl/kubelet
sudo rm -rf /etc/cni/

关键代码解释:

  • systemctl stop:终止所有 k8s 相关服务
  • rm -rf:删除核心配置目录,包括证书、网络插件配置等
  • /etc/cni/:CNI 网络插件的配置目录(如 Calico、Flannel)

2. 网络规则清理(iptables 示例)

# 查看当前 iptables 规则
sudo iptables -L -n

# 删除 k8s 相关规则(需根据实际规则调整)
sudo iptables -D FORWARD -s 10.244.0.0/16 -j DROP
sudo iptables -D FORWARD -d 10.244.0.0/16 -j DROP

关键代码解释:

  • iptables -D:删除指定的规则
  • 10.244.0.0/16:k8s 的默认服务网段,根据实际部署可能不同

3. 证书清理(基于 etcd 的 k8s)

# 查找证书文件
find /etc/ssl/ -name "*.crt" -o -name "*.key"

# 删除证书文件(注意:需确保没有其他服务依赖)
sudo rm /etc/ssl/kubelet/kubelet.crt
sudo rm /etc/ssl/kubelet/kubelet.key

关键代码解释:

  • find:快速定位证书文件
  • rm:删除证书文件,避免残留

五、完整案例

案例:彻底卸载 kubeadm 安装的 k8s

1. 预检查

# 检查运行中的服务
systemctl list-units --type=service | grep kube

# 检查证书文件
find /etc/ssl/ -name "*.crt" -o -name "*.key"

2. 卸载步骤

# 停止服务
sudo systemctl stop kubelet kube-proxy

# 删除配置文件
sudo rm -rf /etc/kubernetes/
sudo rm -rf /var/lib/kubelet/
sudo rm -rf /etc/ssl/kubelet
sudo rm -rf /etc/cni/

# 清理网络规则
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t nat -X

# 恢复默认 cgroup 设置
sudo mount | grep cgroup
sudo umount /sys/fs/cgroup
sudo mount -t cgroup none /sys/fs/cgroup

3. 验证卸载

# 检查残留文件
find / -name "kubernetes" -o -name "kubelet" -o -name "kube-proxy" -o -name "kubeadm"

# 检查服务状态
systemctl list-units --type=service | grep kube

六、源码解析

1. kubeadm 卸载机制

kubeadm reset 命令的核心逻辑如下(简化版):

# kubeadm reset 源码片段(伪代码)
def reset():
    stop_services()
    remove_config_files()
    remove_certificates()
    clean_network_rules()
    restore_system_settings()

关键点:

  • stop_services():通过 systemctl stop 停止服务
  • remove_config_files():删除 /etc/kubernetes/ 目录
  • clean_network_rules():清理 iptables 规则

2. 自定义清理脚本(完整示例)

#!/bin/bash

# 停止服务
sudo systemctl stop kubelet kube-proxy

# 删除配置文件
sudo rm -rf /etc/kubernetes/
sudo rm -rf /var/lib/kubelet/
sudo rm -rf /etc/ssl/kubelet
sudo rm -rf /etc/cni/

# 清理网络规则
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t nat -X

# 恢复默认 cgroup 设置
sudo mount | grep cgroup
sudo umount /sys/fs/cgroup
sudo mount -t cgroup none /sys/fs/cgroup

# 检查残留
find / -name "kubernetes" -o -name "kubelet" -o -name "kube-proxy" -o -name "kubeadm"

关键代码解释:

  • 脚本通过 rm -rf 删除核心目录,避免残留
  • 使用 iptables -F 清理规则,确保网络状态恢复
  • mount 命令用于恢复默认的 cgroup 配置

七、进阶使用

1. 生产环境卸载方案

在生产环境中,建议使用以下流程:

# 先备份数据
sudo tar -czf k8s_backup.tar.gz /etc/kubernetes/ /var/lib/kubelet/

# 卸载流程(同上)

注意事项:

  • 备份关键配置文件(如 kubeconfig)
  • 确认所有节点已卸载
  • 重启系统后检查残留

2. 多节点集群卸载

# 在主节点执行
sudo kubeadm reset

# 在工作节点执行
sudo systemctl stop kubelet
sudo rm -rf /etc/kubernetes/
sudo rm -rf /var/lib/kubelet/
sudo rm -rf /etc/ssl/kubelet
sudo rm -rf /etc/cni/

关键点:

  • 主节点需执行 kubeadm reset 清理集群状态
  • 工作节点仅需删除残留文件

八、性能与工程实践

1. 性能优化

  • 清理顺序:先停止服务再删除文件,避免删除过程中服务重启
  • 批量删除:使用 find 命令批量清理,避免逐个删除
  • 日志保留:保留 /var/log/kube* 日志用于后续调试

2. 异常处理

# 捕获删除失败的文件
sudo find /etc/kubernetes/ -name "*.conf" -exec rm {} \; 2>/dev/null

3. 安全风险

  • 证书安全:删除证书后,需确保未被其他服务引用
  • 权限管理:删除文件时需使用 sudo,避免权限问题
  • 日志清理:保留日志可帮助排查卸载失败原因

九、常见问题与踩坑

1. 问题:残留证书导致新部署失败

错误示例:

sudo kubeadm init --config kubeadm-config.yaml

错误日志:

[ERROR] Certificate for kubelet is not valid

解决方法:

# 删除残留证书
sudo rm /etc/ssl/kubelet/kubelet.crt
sudo rm /etc/ssl/kubelet/kubelet.key

2. 问题:网络规则未清理导致服务异常

错误示例:

sudo systemctl start kubelet

错误日志:

Failed to connect to the API server: Connection refused

解决方法:

# 清理网络规则
sudo iptables -F
sudo iptables -X

3. 问题:cgroup 配置错误导致服务启动失败

错误示例:

sudo systemctl start kubelet

错误日志:

Failed to create cgroup: No such process

解决方法:

# 恢复默认 cgroup 设置
sudo mount -t cgroup none /sys/fs/cgroup

十、最佳实践

1. 推荐方案

  • 使用 kubeadm reset:适用于快速卸载(但可能不彻底)
  • 手动清理:适用于需要完全控制的场景
  • 脚本化处理:提高效率,避免手动错误

2. 使用场景

场景推荐方案
测试环境手动清理 + 脚本
生产环境kubeadm reset + 验证
紧急修复系统重启 + 清理残留

3. 不建议使用的情况

  • 生产环境频繁卸载:可能导致配置不一致
  • 未备份重要配置:可能导致数据丢失
  • 未验证残留文件:可能导致后续部署失败

十一、总结

本文深入解析了 Linux 无残留卸载 k8s 的原理、实现方法和常见问题。通过提供完整代码示例和详细解释,帮助读者理解如何彻底清理 k8s 环境,避免残留问题。在实际开发中,应根据具体场景选择合适的卸载方案,如测试环境推荐使用脚本化清理,生产环境建议结合 kubeadm reset 进行验证。

关键点总结:

  • 卸载需覆盖服务、配置、证书、网络规则等多方面
  • 使用 kubeadm reset 作为基础工具,结合手动清理确保彻底
  • 避免在生产环境中频繁卸载,确保配置一致性
  • 始终验证卸载结果,确保系统回归初始状态

通过本文的方法,开发者可以在各种场景下安全、彻底地卸载 k8s,为后续部署或系统维护提供可靠保障。

2024-08-07

【kubernetes】使用KubeSphere部署中间件服务

一、背景与问题

在Kubernetes生态系统中,中间件服务(如数据库、消息队列、缓存系统)的部署是微服务架构中的关键环节。传统部署方式需要开发者手动编写Deployment、Service、ConfigMap等资源对象,且需要处理持久化存储、配置管理、权限控制等复杂问题。KubeSphere作为基于Kubernetes的开源平台,通过图形化界面和智能模板系统,为中间件服务的部署提供了更高效的解决方案。

然而,在实际开发中仍然面临诸多挑战:

  • 中间件配置参数需要通过环境变量或ConfigMap传递,但参数组合复杂
  • 持久化存储需要考虑存储类、访问模式和备份策略
  • 跨团队协作时需要统一的配置规范
  • 安全性要求(如Secret管理、访问控制)需要额外处理

本文将深入解析KubeSphere在中间件部署中的技术原理,结合真实项目场景展示完整部署流程。

二、基本原理

KubeSphere通过以下核心机制实现中间件服务的高效部署:

1. 资源抽象层

KubeSphere通过图形化界面抽象了Kubernetes的原始资源对象,将复杂的Deployment/Service结构转化为可视化配置面板。每个中间件服务的部署都对应一个"应用"实例,包含:

  • 资源需求(CPU/内存)
  • 配置参数(通过Env或ConfigMap)
  • 网络策略(Service类型)
  • 存储需求(PersistentVolumeClaim)
  • 安全策略(RBAC权限)

2. 配置管理机制

KubeSphere支持两种配置管理方式:

  • Secret模式:通过加密的Secret对象存储敏感参数(如数据库密码)
  • ConfigMap模式:存储非敏感配置参数(如日志级别、超时设置)

这两种模式通过环境变量注入到容器中,支持动态更新。

3. 持久化存储管理

KubeSphere提供了存储类选择器,开发者可指定:

  • 存储类型(如SSD、HDD)
  • 访问模式(ReadWriteOnce/ReadWriteMany)
  • 存储容量(通过StorageClass动态配置)

4. 自动化运维

通过Operator模式,KubeSphere支持中间件的自动扩缩容、健康检查、备份恢复等功能。例如MySQL实例可配置自动备份策略,Redis集群可实现自动故障转移。

三、环境准备

1. 系统要求

  • Kubernetes集群(1.20+)
  • KubeSphere v3.2.0+
  • Docker 19+
  • kubectl 1.20+

2. 安装KubeSphere

# 安装KubeSphere
kubectl apply -f https://raw.githubusercontent.com/kubesphere/kubesphere/main/installer/deployments/kubesphere-dashboard.yaml
kubectl apply -f https://raw.githubusercontent.com/kubesphere/kubesphere/main/installer/deployments/etcd.yaml
kubectl apply -f https://raw.githubusercontent.com/kubesphere/kubesphere/main/installer/deployments/kube-apiserver.yaml

3. 验证安装

kubectl get ns | grep kubesphere
# 应输出 kubesphere-system 空间

四、核心实现

1. 部署MySQL中间件(示例1)

# mysql-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-data
        persistentVolumeClaim:
          claimName: mysql-pvc
# 创建Secret
kubectl create secret generic mysql-secret \
  --from-literal=password=123456 \
  --namespace=default
# 创建PersistentVolumeClaim
kubectl apply -f mysql-pvc.yaml

2. 配置持久化存储(示例2)

# mysql-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 10Gi

3. 配置网络策略(示例3)

# mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: default
spec:
  type: ClusterIP
  ports:
  - port: 3306
    protocol: TCP
  selector:
    app: mysql

五、完整案例

1. 部署带监控的Redis服务(完整案例)

1.1 创建Namespace

kubectl create namespace redis

1.2 部署Redis主从集群

# redis-cluster.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
  namespace: redis
spec:
  serviceName: redis
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:6.2
        ports:
        - containerPort: 6379
        env:
        - name: REDIS_REPLICATION_MODE
          value: "cluster"
        volumeMounts:
        - name: redis-data
          mountPath: /data
      volumes:
      - name: redis-data
        persistentVolumeClaim:
          claimName: redis-pvc
# 创建PersistentVolumeClaim
kubectl apply -f redis-pvc.yaml

1.3 配置监控

# prometheus-redis.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: redis-monitor
  namespace: redis
spec:
  selector:
    matchLabels:
      app: redis
  endpoints:
  - port: 9121
    interval: 10s

六、源码解析

1. KubeSphere的Operator模式

KubeSphere通过Operator模式实现中间件的自动运维。以MySQL为例,Operator会持续监控集群状态,当检测到实例异常时会自动重启容器。核心逻辑如下:

// mysql-operator.go
func (r *MySQLReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
    // 检查实例状态
    instance := &mysqlv1.MySQL{}
    if err := r.Client.Get(context.TODO(), req.NamespacedName, instance); err != nil {
        log.Info("MySQL instance not found")
        return ctrl.Result{}, nil
    }

    // 检查健康状态
    if instance.Status.Health != "healthy" {
        log.Info("MySQL instance is unhealthy, restarting...")
        // 执行重启操作
        return ctrl.Result{Requeue: true}, nil
    }
    
    return ctrl.Result{}, nil
}

2. 配置管理机制

KubeSphere通过ConfigMap和Secret的结合实现配置管理,关键代码如下:

// configmanager.go
func (c *ConfigManager) injectConfig(envs []corev1.EnvVar) {
    for _, env := range envs {
        if strings.HasPrefix(env.Name, "MYSQL_") {
            // 加密敏感参数
            if strings.Contains(env.Name, "PASSWORD") {
                secret := &corev1.Secret{}
                if err := c.Client.Get(context.TODO(), types.NamespacedName{
                    Name:      "mysql-secret",
                    Namespace: "default",
                }, secret); err != nil {
                    log.Error("Failed to get secret", err)
                }
                // 解密处理
            } else {
                // 非敏感参数直接注入
            }
        }
    }
}

七、进阶使用

1. 自定义中间件模板

KubeSphere支持自定义部署模板,通过YAML文件定义中间件的部署规范:

# custom-middleware.yaml
apiVersion: kubesphere.io/v1beta1
kind: Application
metadata:
  name: my-custom-middleware
  namespace: default
spec:
  type: helm
  source:
    chart: ./my-middleware-chart
  parameters:
    - name: database
      value: mysql
    - name: replicas
      value: "3"

2. 持久化存储策略优化

对于高并发场景,建议使用以下策略:

  • 使用SSD存储类
  • 配置存储QoS(Quality of Service)
  • 启用存储自动扩展
# storage-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  iopsPerGB: "100"
  fsType: ext4

八、性能与工程实践

1. 性能优化策略

优化维度建议方案原理说明
CPU/内存设置资源限制防止资源争抢
网络使用Cilium网络策略提升网络性能
存储使用本地SSD降低IO延迟
持久化启用备份策略防止数据丢失

2. 安全实践

  • 使用RBAC限制访问权限
  • 对Secret进行加密存储
  • 启用网络策略(NetworkPolicy)
  • 定期更新镜像版本

3. 异常处理机制

# error-handling.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: error-handling
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1

九、常见问题与踩坑

1. 常见错误及解决方案

问题原因解决方案
服务无法访问Service类型错误修改为ClusterIP或NodePort
配置未生效Secret名称错误检查Secret名称和Key
存储卷未挂载PVC绑定失败检查StorageClass配置
安全策略冲突RBAC权限不足修改ServiceAccount权限

2. 典型错误示例

# 错误示例:未设置存储类
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: bad-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

错误原因:未指定storageClassName,导致PVC无法绑定PV。

改进方案:

spec:
  storageClassName: standard

十、最佳实践

1. 推荐部署方案

场景推荐方案适用场景
快速部署使用KubeSphere图形界面团队协作、快速原型
高可用部署StatefulSet数据库、缓存集群
安全敏感使用Secret+RBAC金融、医疗系统
资源优化自定义StorageClass生产环境资源控制

2. 推荐配置规范

  • 使用ConfigMap存储非敏感配置
  • 对敏感参数使用Secret
  • 所有中间件部署在独立的Namespace
  • 配置健康检查端点
  • 启用自动备份策略

十一、总结

KubeSphere通过资源抽象、配置管理、持久化存储和自动运维等核心机制,显著简化了中间件服务的部署流程。在实际项目中,建议优先考虑以下场景:

  • 需要快速部署的微服务架构
  • 团队协作开发的多环境管理
  • 需要统一配置管理的混合云环境

但需要注意避免以下情况:

  • 需要高度定制化配置的特殊业务
  • 资源受限的边缘计算场景
  • 需要精细化资源控制的生产环境

通过合理使用KubeSphere的高级功能,结合正确的配置实践,可以显著提升中间件服务的部署效率和系统稳定性。在实际开发中,建议结合团队的具体需求,选择最合适的部署方案。

2024-08-07

k8s集群下mysql容器更换pvc存储迁移数据,报错InnoDB: Your database may be corrupt

一、背景与问题

在Kubernetes集群中,MySQL容器通常通过PersistentVolumeClaim(PVC)实现持久化存储。当需要更换PVC(如扩容、迁移、故障转移等场景)时,直接替换PVC会导致InnoDB引擎检测到数据文件不一致,触发"InnoDB: Your database may be corrupt"的严重警告。

这种问题的根源在于:MySQL在运行时会为数据文件加锁,直接替换PVC会导致文件系统不一致、文件锁残留、文件损坏等问题。特别是在容器化环境中,Pod的生命周期管理、存储卷挂载机制、文件系统同步等细节都可能引发问题。

二、基本原理

1. MySQL存储结构

MySQL的InnoDB存储引擎使用ibdata1文件作为系统表空间,ib_logfile0/ib_logfile1作为日志文件,以及多个表空间文件(如tablespace_name.ibd)。这些文件在容器中被挂载到PVC后,会直接暴露给MySQL进程。

2. 文件系统一致性要求

InnoDB引擎在启动时会进行文件系统检查,确保:

  • 数据文件未被截断
  • 文件系统未发生不一致
  • 文件锁未被残留
  • 日志文件未被损坏

3. Kubernetes存储卷替换机制

当替换PVC时,Kubernetes会执行以下流程:

  1. 删除旧PVC
  2. 创建新PVC
  3. 更新Deployment/StatefulSet的volumeClaimTemplates
  4. 重新调度Pod挂载新PVC

但此流程不保证:

  • 数据文件的完整性
  • 文件锁的释放
  • 文件系统的一致性

三、环境准备

# 创建命名空间
kubectl create namespace mysql-migration

# 创建StorageClass(以AWS EBS为例)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp2
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
reclaimPolicy: Delete
mountOptions:
  - nosuid
  - nodev
  - nodiratime
allowVolumeExpansion: true
# PVC模板示例
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data
  namespace: mysql-migration
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: gp2
  resources:
    requests:
      storage: 10Gi

四、核心实现

1. 安全迁移流程(推荐方案)

# 1. 停止MySQL容器
kubectl exec -it mysql-0 -- pkill mysql

# 2. 检查文件系统状态
kubectl exec -it mysql-0 -- dumpeibd -d /var/lib/mysql

# 3. 复制数据文件
kubectl exec -it mysql-0 -- tar -czvf /tmp/mysql-data.tar.gz /var/lib/mysql

# 4. 将数据文件复制到新PVC
kubectl cp mysql-0:/tmp/mysql-data.tar.gz . 
kubectl create configmap mysql-data --from-file=mysql-data.tar.gz -n mysql-migration

# 5. 更新StorageClass(可选)
kubectl patch storageclass gp2 -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

2. InnoDB文件检查工具

# 检查InnoDB文件状态
kubectl exec -it mysql-0 -- innodb_check --innodb_data_file_path=ibdata1:10M

# 检查日志文件
kubectl exec -it mysql-0 -- grep 'InnoDB: log file' /var/log/mysql/error.log

# 检查文件锁
kubectl exec -it mysql-0 -- lsof | grep 'ibdata1'

3. 容器内文件同步工具

# 使用rsync同步数据文件
kubectl exec -it mysql-0 -- rsync -avz /var/lib/mysql/ /mnt/new-pvc/

五、完整案例

1. 场景描述

某电商平台需要将MySQL存储从10Gi扩容到50Gi,需更换PVC。

2. 实施步骤

# 1. 创建新StorageClass
kubectl apply -f storageclass.yaml

# 2. 创建新PVC
kubectl apply -f new-pvc.yaml

# 3. 更新StatefulSet配置
kubectl edit statefulset mysql -n mysql-migration

# 4. 检查Pod状态
kubectl get pods -n mysql-migration

# 5. 停止旧Pod
kubectl delete pod mysql-0 -n mysql-migration

# 6. 检查文件系统一致性
kubectl exec -it mysql-1 -- dumpeibd -d /var/lib/mysql

# 7. 验证数据完整性
kubectl exec -it mysql-1 -- mysqlcheck --all-databases

3. 故障恢复方案

# 1. 恢复数据文件
kubectl cp mysql-data.tar.gz mysql-1:/tmp/ -n mysql-migration

# 2. 解压数据文件
kubectl exec -it mysql-1 -- tar -xzvf /tmp/mysql-data.tar.gz

# 3. 修复文件系统
kubectl exec -it mysql-1 -- fsck /dev/mapper/... 

六、源码解析

1. InnoDB文件检查源码

// innodb_check.c
void innodb_check() {
    // 检查文件系统一致性
    if (fstat(fd, &st) != 0) {
        fprintf(stderr, "InnoDB: File system inconsistency detected\n");
        exit(EXIT_FAILURE);
    }

    // 检查文件锁
    if (fcntl(fd, F_GETLK, &lock) != 0) {
        fprintf(stderr, "InnoDB: File lock detected\n");
        exit(EXIT_FAILURE);
    }
}

2. Kubernetes文件同步源码

// k8s-migration.go
func syncDataFiles(src, dst string) error {
    cmd := exec.Command("rsync", "-avz", src, dst)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    return cmd.Run()
}

3. 存储卷替换源码

# statefulset.yaml
spec:
  volumes:
    - name: mysql-data
      persistentVolumeClaim:
        claimName: mysql-data

七、进阶使用

1. 多版本兼容性处理

# 检查MySQL版本兼容性
kubectl exec -it mysql-0 -- mysql --version

# 检查存储版本兼容性
kubectl get storageclass -n mysql-migration

2. 高可用架构改造

# 配置MySQL主从复制
kubectl exec -it mysql-0 -- mysql -e "CHANGE MASTER TO MASTER_HOST='mysql-1', MASTER_USER='repl', MASTER_PASSWORD='secret'"

# 配置GTID复制
kubectl exec -it mysql-0 -- mysql -e "SET GLOBAL GTID_MODE=ON"

3. 自动化迁移脚本

#!/bin/bash
# 自动化迁移脚本
kubectl exec -it mysql-0 -- pkill mysql
kubectl cp mysql-data.tar.gz mysql-1:/tmp/ -n mysql-migration
kubectl exec -it mysql-1 -- tar -xzvf /tmp/mysql-data.tar.gz
kubectl exec -it mysql-1 -- mysqlcheck --all-databases

八、性能与工程实践

1. 性能优化方案

# 使用压缩传输
kubectl exec -it mysql-0 -- tar -czvf /tmp/mysql-data.tar.gz /var/lib/mysql

# 使用多线程同步
kubectl exec -it mysql-0 -- rsync -avz --multi-threaded /var/lib/mysql/ /mnt/new-pvc/

2. 安全风险分析

风险类型描述解决方案
权限泄露新PVC未配置RBAC使用Kubernetes Role-Based Access Control
数据泄露未加密传输使用TLS加密传输
系统漏洞未更新MySQL版本定期更新MySQL版本

3. 性能监控方案

# 监控InnoDB状态
kubectl exec -it mysql-0 -- mysql -e "SHOW ENGINE INNODB STATUS\G"

# 监控文件系统
kubectl exec -it mysql-0 -- df -h

九、常见问题与踩坑

1. 常见错误分析

错误类型原因解决方案
文件锁残留未正确关闭MySQL进程使用pkill mysql强制终止
文件系统不一致未检查文件系统使用fsck检查文件系统
数据文件损坏未验证数据完整性使用mysqlcheck验证数据

2. 典型错误示例

# 错误示例:直接替换PVC
kubectl delete pvc mysql-data
kubectl apply -f new-pvc.yaml
# 正确做法:先备份数据
kubectl exec -it mysql-0 -- mysqldump --all-databases > backup.sql

十、最佳实践

1. 推荐方案

  • 使用kubectl exec安全停止MySQL
  • 使用dumpeibd检查文件系统状态
  • 使用rsync同步数据文件
  • 使用mysqlcheck验证数据完整性

2. 不推荐方案

  • 直接替换PVC
  • 未检查文件系统
  • 未验证数据完整性
  • 未配置RBAC权限

3. 实施建议

  • 在非业务高峰时段进行
  • 使用多副本架构保证高可用
  • 使用监控系统跟踪迁移过程
  • 定期进行数据验证

十一、总结

在Kubernetes集群中更换MySQL的PVC存储时,必须充分理解InnoDB文件系统的工作原理。通过安全停止MySQL服务、验证文件系统一致性、同步数据文件、检查数据完整性等步骤,可以有效避免"InnoDB: Your database may be corrupt"的错误。

在实际项目中,建议:

  • 在需要扩容/迁移时,优先使用备份恢复方案
  • 对关键数据实施双副本存储
  • 配置完善的监控和告警系统
  • 使用自动化脚本提高操作效率

同时也要注意:

  • 避免直接替换PVC
  • 不要忽略文件系统检查
  • 不要省略数据验证步骤
  • 不要忽略安全配置

通过深入理解底层原理和掌握正确的操作流程,可以在Kubernetes环境中安全、高效地管理MySQL的持久化存储。

2024-08-07

Jenkins 部署 Golang 应用到 Kubernetes 与测试环境

一、背景与问题

在现代云原生开发中,Golang 应用通常需要经过开发、测试、生产等多个环境的部署流程。Kubernetes(K8s)作为容器编排系统,提供了强大的自动化部署能力,而 Jenkins 作为老牌 CI/CD 工具,能与 K8s 高效集成。但实际开发中常遇到以下问题:

  • 如何实现持续交付的自动化闭环?
  • 如何确保测试环境与生产环境的镜像一致性?
  • 如何在 Jenkins 中高效管理多环境部署?
  • 如何处理构建缓存、镜像版本控制等复杂场景?

本文将深入解析 Jenkins 与 K8s 集成的完整流程,结合真实项目场景,探讨其适用性与最佳实践。

二、基本原理

Jenkins 与 K8s 的集成涉及三个核心流程:

  1. 代码构建:通过 Jenkins Pipeline 拉取代码、编译 Golang 应用
  2. 容器化:使用 Docker 构建镜像并推送到镜像仓库(如 Harbor/Quay)
  3. K8s 部署:通过 kubectl 或 Helm 实现应用部署

Golang 应用的特殊性在于:

  • 需要处理依赖管理(Go modules)
  • 需要构建可执行文件
  • 需要处理多环境配置(开发/测试/生产)

三、环境准备

1. 基础环境要求

  • Jenkins 服务器(可使用 Docker 安装)
  • Kubernetes 集群(可使用 kubeadm/kops 或云服务)
  • Docker 引擎(需配置镜像仓库权限)
  • 基础依赖:

    # 安装基础工具
    sudo apt-get install -y docker.io kubectl helm

2. Jenkins 配置

创建 Jenkins 服务账户(ServiceAccount):

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-deploy
  namespace: default
secrets:
- name: jenkins-token

配置 RBAC 权限:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: jenkins-role
rules:
- apiGroups: [""]
  resources: ["pods", "services", "secrets"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]

四、核心实现

1. Jenkins Pipeline 构建流程

完整 Jenkinsfile 示例(支持多环境部署):

pipeline {
    agent any
    environment {
        DOCKER_REGISTRY = 'harbor.example.com'
        K8S_NAMESPACE = 'prod'
        TEST_NAMESPACE = 'test'
    }
    stages {
        stage('Checkout') {
            steps {
                git url: 'https://github.com/yourrepo/yourproject.git', branch: 'main'
            }
        }
        stage('Build') {
            steps {
                sh 'go mod tidy'
                sh 'GOOS=linux GOARCH=amd64 go build -o app'
            }
        }
        stage('Docker Build') {
            steps {
                script {
                    docker.build("golang-app:${env.BUILD_ID}", ".")
                }
            }
        }
        stage('Push to Registry') {
            steps {
                script {
                    docker.withRegistry("${env.DOCKER_REGISTRY}", 'harbor-credentials') {
                        docker.image.push("golang-app:${env.BUILD_ID}")
                    }
                }
            }
        }
        stage('Deploy to K8s') {
            steps {
                script {
                    sh 'kubectl apply -f k8s/deployment.yaml'
                }
            }
        }
        stage('Deploy to Test') {
            steps {
                script {
                    sh 'kubectl apply -f k8s/test-deployment.yaml'
                }
            }
        }
    }
}

关键代码解释:

  • 使用 GOOS=linux 构建跨平台可执行文件
  • 通过 docker.build 实现本地构建
  • 使用 docker.withRegistry 管理镜像仓库凭证
  • 分离生产/测试环境的部署配置

2. Dockerfile 设计(多阶段构建)

# 阶段1:构建阶段
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go mod tidy
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app

# 阶段2:最终镜像
FROM alpine:3.18
WORKDIR /root
COPY --from=builder /app/app /root/app
ENTRYPOINT ["./app"]

多阶段构建优势:

  • 减少最终镜像体积(<10MB)
  • 隔离构建过程与运行环境
  • 支持不同架构的构建(如 arm64)

3. Kubernetes 部署配置(生产环境)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: golang-app
  namespace: prod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: golang-app
  template:
    metadata:
      labels:
        app: golang-app
    spec:
      containers:
      - name: golang-app
        image: harbor.example.com/golang-app:latest
        ports:
        - containerPort: 8080
        env:
        - name: ENV
          value: "prod"
      imagePullSecrets:
      - name: harbor-credentials

关键配置说明:

  • 使用 imagePullSecrets 管理镜像仓库凭证
  • 通过环境变量区分环境
  • 配置副本数(3个)实现高可用

五、完整案例

1. 项目结构

.
├── Jenkinsfile
├── Dockerfile
├── k8s
│   ├── deployment.yaml
│   └── test-deployment.yaml
├── go.mod
├── go.sum
└── main.go

2. 完整部署流程

  1. 代码提交:开发者提交代码到 GitHub
  2. Jenkins 触发:通过 webhook 触发 Jenkins Pipeline
  3. 代码拉取:Jenkins 拉取代码并进行模块整理
  4. 构建编译:使用 Golang 构建可执行文件
  5. 容器化:使用多阶段 Dockerfile 构建镜像
  6. 镜像推送:将镜像推送到私有仓库
  7. K8s 部署:通过 kubectl 应用配置文件
  8. 测试验证:通过测试环境验证功能
  9. 生产部署:根据 CI/CD 策略进行生产部署

3. 完整 Jenkinsfile 示例

pipeline {
    agent {
        docker {
            image 'maven:3.8.6-jdk-17'
            args 'gcr.io/distroless/java:17'
        }
    }
    environment {
        DOCKER_REGISTRY = 'harbor.example.com'
        K8S_NAMESPACE = 'prod'
        TEST_NAMESPACE = 'test'
        GITHUB_TOKEN = credentials('github-token')
    }
    stages {
        stage('Build') {
            steps {
                sh 'go mod tidy'
                sh 'GOOS=linux GOARCH=amd64 go build -o app'
            }
        }
        stage('Docker Build') {
            steps {
                script {
                    docker.build("golang-app:${env.BUILD_ID}", ".")
                }
            }
        }
        stage('Push to Registry') {
            steps {
                script {
                    docker.withRegistry("${env.DOCKER_REGISTRY}", 'harbor-credentials') {
                        docker.image.push("golang-app:${env.BUILD_ID}")
                    }
                }
            }
        }
        stage('Deploy to K8s') {
            steps {
                script {
                    sh 'kubectl apply -f k8s/deployment.yaml'
                }
            }
        }
        stage('Deploy to Test') {
            steps {
                script {
                    sh 'kubectl apply -f k8s/test-deployment.yaml'
                }
            }
        }
    }
}

4. 完整 Deployment 配置(测试环境)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: golang-app-test
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: golang-app-test
  template:
    metadata:
      labels:
        app: golang-app-test
    spec:
      containers:
      - name: golang-app
        image: harbor.example.com/golang-app:latest
        ports:
        - containerPort: 8080
        env:
        - name: ENV
          value: "test"
      imagePullSecrets:
      - name: harbor-credentials

六、源码解析

1. Jenkins Pipeline 关键点

  • 使用 docker.build 实现本地构建,避免网络依赖
  • 通过 environment 管理不同环境的配置
  • 使用 docker.withRegistry 管理凭证,提高安全性

2. Dockerfile 多阶段构建

  • 第一阶段构建可执行文件,第二阶段打包运行时依赖
  • 避免将构建工具包含在最终镜像中
  • 支持构建不同架构的镜像(如 arm64)

3. Kubernetes 配置关键点

  • 使用 imagePullSecrets 管理镜像仓库凭证
  • 通过环境变量区分环境(prod/test)
  • 配置副本数(3个)实现高可用
  • 使用标签策略(latest/semver)管理镜像版本

七、进阶使用

1. 环境变量管理

通过 Kubernetes ConfigMap 管理配置:

apiVersion: v1
kind: ConfigMap
metadata:
  name: golang-app-config
  namespace: prod
data:
  ENV: prod
  LOG_LEVEL: info

在 Deployment 中引用:

containers:
- env:
  - name: ENV
    valueFrom:
      configMapKeyRef:
        name: golang-app-config
        key: ENV

2. 自动化测试集成

在 Jenkins Pipeline 中增加测试阶段:

stage('Run Tests') {
    steps {
        sh 'go test -v ./...'
    }
}

3. 镜像版本控制

使用 Git commit hash 作为镜像标签:

def commitHash = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
docker.build("golang-app:${commitHash}", ".")

八、性能与工程实践

1. 构建性能优化

  • 使用构建缓存(--mount=type=cache)
  • 启用 Go 编译器优化(-gcflags="-l")
  • 使用构建策略(buildkite.com 等工具)

2. 镜像大小优化

  • 压缩静态文件(使用 gzip)
  • 删除不必要的依赖(go mod tidy)
  • 使用 slim 基础镜像(alpine:3.18)

3. K8s 资源管理

  • 设置资源限制(resources.limits)
  • 使用 HPA 实现自动扩缩容
  • 配置 Pod 重启策略(restartPolicy: Always)

4. 安全性考虑

  • 使用 Secret 管理敏感信息(Kubernetes Secrets)
  • 禁用不必要的容器功能(securityContext)
  • 配置网络策略(NetworkPolicy)

九、常见问题与踩坑

1. 常见错误

错误示例:

Error: failed to pull image: unauthorized: authentication required

原因分析:

  • 镜像仓库未配置凭证
  • Jenkins 配置的 registry URL 错误

解决办法:

  • 在 Jenkins 中配置 registry 凭证(使用 credentials)
  • 验证 registry URL 是否正确(docker info)

2. 构建缓存问题

错误示例:

go mod tidy: no go.mod file in current directory

原因分析:

  • 缺少 go.mod 文件
  • 未正确初始化模块

解决办法:

  • 确保项目包含 go.mod 文件
  • 使用 go mod init 初始化模块

3. K8s 部署失败

错误示例:

Error: failed to create pod: invalid character in identifier

原因分析:

  • 配置文件中存在非法字符
  • 资源名称不符合命名规范

解决办法:

  • 使用 kubectl apply --dry-run=client 验证配置
  • 遵循 Kubernetes 命名规范(小写字母、短横线分隔)

十、最佳实践

  1. 使用多阶段构建:确保最终镜像体积最小
  2. 区分环境配置:通过环境变量和 ConfigMap 管理配置
  3. 自动化测试集成:在 CI/CD 流程中加入测试阶段
  4. 版本控制策略:使用 commit hash 或 semantic versioning 管理镜像版本
  5. 安全加固:使用 Secret 管理敏感信息,配置网络策略
  6. 性能优化:使用缓存、资源限制、HPA 等机制提升性能

十一、总结

Jenkins 与 Kubernetes 的集成是实现持续交付的关键环节。通过合理的 Pipeline 设计、容器化方案和 K8s 配置,可以实现从代码提交到生产部署的全自动化流程。但在实际项目中需要根据具体情况选择合适方案:

适合使用的情况:

  • 需要跨平台部署的项目
  • 需要多环境管理的项目
  • 需要自动化测试的项目

不建议使用的情况:

  • 极小规模项目(可直接部署服务器)
  • 对 K8s 不熟悉的团队
  • 需要极低延迟的实时系统

通过本文的深入分析,希望能帮助开发者更好地理解 Jenkins 与 K8s 集成的原理和实践,构建可靠的持续交付体系。