Bài viết này mình sẽ tóm tắt cách thiết lập Jenkins trên Kubenretes và thực hiện một job đơn giản.
Về cơ bản, chúng ta deploy Jenkins master, con các agent sẽ được khởi tạo mỗi khi job chạy, sau khi job hoàn thành thì tự động được xóa, agent này chính là các pod của Kubernetes cluster.
Như vậy hệ thống Jenkins CI/CD sẽ có khả năng scale up dễ dàng. Vui lòng xem các bài viết trước để biết cách mà mình xây dụng Kubernetes cluster trên máy chủ chạy Microsoft Hyper-V Server. Bây giờ chúng ta sẽ bắt đầu.
Cấu hình các Resources của K8s
Mình không sử dụng Helm, dưới đây là các file yaml
cấu hình các resource sẽ khởi tạo trên K8s cluster.
deployment.yaml
Mình sử dụng docker image ghcr.io/nvtienanh/jenkins-master:latest dựa trên image gốc jenkins:alpine nhưng được cài đặt sẵn một vài plugin:
- kubernetes
- kubernetes-cli
- ldap
- git
- …
apiVersion: apps/v1 kind: Deployment metadata: name: jenkins labels: app: jenkins namespace: jenkins spec: replicas: 1 selector: matchLabels: app: jenkins template: metadata: labels: app: jenkins spec: containers: - name: jenkins image: ghcr.io/nvtienanh/jenkins-master:latest imagePullPolicy: Always env: - name: LIMITS_MEMORY valueFrom: resourceFieldRef: resource: limits.memory divisor: 1Mi - name: JAVA_OPTS value: -Djenkins.install.runSetupWizard=false -Xmx$(LIMITS_MEMORY)m -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 ports: - name: http containerPort: 8080 - name: jnlp containerPort: 50000 volumeMounts: - name: jenkins-home mountPath: /var/jenkins_home volumes: - name: jenkins-home persistentVolumeClaim: claimName: jenkins-pvc
service.yaml
apiVersion: v1 kind: Service metadata: labels: app: jenkins namespace: jenkins name: jenkins spec: type: LoadBalancer ports: - name: http port: 80 targetPort: 8080 protocol: TCP - name: jnlp port: 50000 targetPort: 50000 protocol: TCP selector: app: jenkins
ingress.yaml
- File này định nghĩa Ingress, cần phải sửa lại jenkins.yourdomain.com thành domain jenkins của bạn.
- Mình sử dụng ssl
letsencrypt-dev
để dùng https khi truy cập vào jenkins server xem thêm trong file cluster-issuer.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: jenkins namespace: jenkins labels: app: jenkins annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-dev spec: tls: - hosts: - jenkins.yourdomain.com secretName: ssl-jenkins rules: - host: jenkins.yourdomain.com http: paths: - path: / pathType: Prefix backend: service: name: jenkins port: number: 80
cluster-issuer.yaml
- letsencrypt-dev: là selfSigned certificate dùng trong môi trường dev
- letsencrypt-staging: letsencrypt staging dùng trong môi trường staging. Sau khi mọi thử ok dùng ssl staging này để kiểm tra.
- letsencrypt-prod: ssl certificate dùng trong môi trường production.
# Dev ClusterIssue apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-dev spec: selfSigned: {} --- # Staging ClusterIssue apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: # The ACME server URL server: https://acme-staging-v02.api.letsencrypt.org/directory # Email address used for ACME registration email: your@email.com # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-staging # Enable the HTTP-01 challenge provider solvers: - http01: ingress: class: nginx # Production ClusterIssue --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: # The ACME server URL server: https://acme-v02.api.letsencrypt.org/directory # Email address used for ACME registration email: your@email.com # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-prod # Enable the HTTP-01 challenge provider solvers: - http01: ingress: class: nginx
storage.yaml
File này định nghĩa phương thức lưu dữ liệu của Jenkins, các log, build report sẽ được lưu trên này. Trong này mình lưu trên NFS server, các bạn có thể sử dụng theo loại storage của mình (nhớ tên
dùng ở Deployment)jenkins-pvc
apiVersion: v1 kind: PersistentVolume metadata: name: jenkins-pv labels: app: jenkins nfs-subdir-external-provisioner: nfs-subdir-external-provisioner spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Delete storageClassName: "" mountOptions: - nfsvers=3 nfs: server: 10.10.0.1 path: /c/jenkins --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: jenkins-pvc namespace: jenkins labels: app: jenkins spec: accessModes: - ReadWriteMany volumeMode: Filesystem storageClassName: "" selector: matchLabels: app: jenkins nfs-subdir-external-provisioner: nfs-subdir-external-provisioner resources: requests: storage: 10Gi
jenkins-service-account.yaml
File này sẽ định nghĩa 1 Service Account (SA) dành cho Jenkins master, nhờ đó mà jenkins có thể sử dụng các resource của Kubernetes cluster.
Tùy theo nhu cầu riêng mà có thể thêm bớt các quyền và phạm vi sử dụng của của SA. Tham khảo thêm trên google nhé.
apiVersion: v1 kind: ServiceAccount metadata: name: jenkins namespace: jenkins --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: jenkins namespace: jenkins rules: - apiGroups: [""] resources: ["pods"] verbs: ["create","delete","get","list","patch","update","watch"] - apiGroups: [""] resources: ["pods/exec"] verbs: ["create","delete","get","list","patch","update","watch"] - apiGroups: [""] resources: ["pods/log"] verbs: ["get","list","watch"] - apiGroups: [""] resources: ["events"] verbs: ["watch"] - apiGroups: [""] resources: ["secrets"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: jenkins namespace: jenkins roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: jenkins subjects: - kind: ServiceAccount name: jenkins
Cài đặt Jenkins
Upload các file yaml lên Microsoft Hyper-V Server bằng Windows Admin Center, sau đó mở PowerShell của server.
kubectl create namespace jenkins kubectl apply -f .\deployment.yaml kubectl apply -f .\service.yaml kubectl apply -f .\storage.yaml kubectl apply -f .\cluster-issuer.yaml kubectl apply -f .\ingress.yaml kubectl apply -f .\jenkins-service-account.yaml
Bạn có thể mở Kubernetes Dashboard để kiểm tra xem các resources đã được deploy thành công hay chưa.
Cấu hình Jenkins và Kubernetes
Truy cập vào Jenkins tại đường dẫn https://jenkins.yourdomain.com để thiết lập.
Vào Manage Jenkins -> Manage Nodes and Clouds -> Configure Cloud. Rồi chọn Add a new cloud Kubernetes.
- Kubernetes URL: https://ip-master-node:6443, giá trị này lấy từ lệnh
kubectl cluster-info
- Jenkins URL: http://jenkins
- Tạo mới Pod Template:
- Name: jenkins-slave
- Namespace: jenkins
- Label: jenkins-slave
- Usage: Only build jobs with label expressions matching this node.
- Tạo mới Container Template
- Name: jnlp
- Docker image: ghcr.io/nvtienanh/jenkins-dind-kubectl:latest
- Host Path Volume:
- Host Path: /var/run/docker.sock
- Mount Path: /var/run/docker.sock
Bước tiếp theo, lưu token của K8s Service Account vào Jenkins Credential. Vào Powershell của Hyper-V Server:
$secret_name = (kubectl get sa jenkins -n jenkins -o json | ConvertFrom-Json).secrets[0].name $token = (kubectl get secret $secret_name -n jenkins -o json | ConvertFrom-Json).data.token $DecodedToken=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($token)) Write-Host $DecodedToken
Copy kết quả trả về vào 1 trình soạn thảo để xóa các ký tự xuống dòng. Tiếp theo bên phía Jenkins:
Vào Manage Jenkins -> Manage Credentials -> Add Credentials:
- Kind: Secret text
- Scope: Global
- Secret: token từ Powershell đã xóa các ký tự xuống dòng ở trên.
- ID: đặt tên gợi nhớ tùy ý
Ok, bây giờ trở lại phần Manage Jenkins -> Manage Nodes and Clouds -> Configure Cloud. Trong phần Credentials chọn Jenkins Service Account.
Chạy thử Jenkins Pipeline
Tạo thử một Pipeline
pipeline { agent { label 'jenkins-slave' } stages { stage('Check version') { steps { sh 'docker version' sh 'kubectl version' } } } }