Published on

Cài đặt Jenkins master - slave dùng Kubernetes

Vừa rồi mình mất khá mất thời gian để khôi phục lại các bài viết cũ bên wordpress để chuyển qua đây. Mất thời gia chỉnh sửa khá nhiều nhất là các công thức viết bằng Latex, các bài viết có thể cũ quá nhưng hy vọng vẫn có ích với nhiều người khác :smile:, bắt đầu câu chuyện của hôm nay:

Hiện tại mình đang làm giải Digital Transformation (Chuyển đổi số, số hóa) cho một đơn vị, một trong các nhiệm vụ đặt ra là xây dựng quy trình phát triển phần mềm cho công ty. Vào thời điểm hiện tại mô hình Scrum - Agile (Quy trình phát triển phần mềm Scrum theo phương pháp Agile) có thể nói đang là xu hướng được rất nhiều công ty phần mềm áp dụng. Không nằm ngoài xu thế đó, team mình cũng bắt đầu áp dụng triển khai, một trong những quy trình đầu tiên đó là Automation Deploy/Testing source code.

Sau khi tham khảo nhiều mô hình, mình quyết định áp dụng Jenkins CI/CD và triển khai trên máy chủ của công ty lúc này chỉ đơn giản 1 con desktop cấu hình mạnh. Dưới đây là các bước chi tiết.

Cài đặt Microk8s

Xem hướng dẫn cài Microk8s trên Ubuntu

Deploy

Tạo namespace

Đầu tiên chúng ta khởi tạo namespace với tên jenkins

# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: jenkins

Tạo PersistentVolume

# jenkins-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: jenkins-pv
  labels:
    type: local
  namespace: jenkins
spec:
  storageClassName: manual
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: '/your-path/jenkins-data'

Phần hostPath là thư mục chứa data của Jenkins server, nếu chưa tồn tại bạn cần tạo thư mục đó.

Tạo PersistentVolumeClaim

# jenkins-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: jenkins-pvc
  labels:
    type: local
  namespace: jenkins
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 40Gi
  volumeName: jenkins-pv

Deployment

# deployment.yaml
---
apiVersion: v1
kind: List
items:
  - apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: jenkins-master-deployment
      labels:
        app: jenkins-master
        version: latest
        group: jenkins
      namespace: jenkins
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: jenkins-master
          version: latest
          group: jenkins
      template:
        metadata:
          labels:
            app: jenkins-master
            version: latest
            group: jenkins
        spec:
          securityContext:
            fsGroup: 1000
            runAsUser: 0
          containers:
            - name: jenkins-master
              image: ghcr.io/nvtienanh/jenkins-master:latest
              imagePullPolicy: Always
              env:
                - name: JAVA_OPTS
                  value: -Djenkins.install.runSetupWizard=false
                  # value: -Djenkins.install.runSetupWizard=false -Dhudson.TcpSlaveAgentListener.hostName=jenkins-jnlp.vanphong.local -Dhudson.TcpSlaveAgentListener.port=443
              ports:
                - name: http-port
                  containerPort: 8080
                - name: jnlp-port
                  containerPort: 50000
              volumeMounts:
                - name: jenkins-home
                  mountPath: /var/jenkins_home
          volumes:
            - name: jenkins-home
              persistentVolumeClaim:
                claimName: jenkins-pvc
                readOnly: false
  - apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: jenkins-master
        version: latest
        group: jenkins
      namespace: jenkins
      name: jenkins-master-service
    spec:
      # type: NodePort
      ports:
        - name: http
          port: 8080
          targetPort: 8080
          protocol: TCP
        - name: jnlp
          port: 50000
          targetPort: 50000
          protocol: TCP
      selector:
        app: jenkins-master
        version: latest
        group: jenkins

Tạo Ingress

# ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/add-base-url: 'true'
    nginx.ingress.kubernetes.io/proxy-body-size: '0'
  name: jenkins-ingress
  namespace: jenkins
spec:
  rules:
    - host: jenkins.yourdomain.com
      http:
        paths:
          - backend:
              serviceName: jenkins-master-service
              servicePort: 8080
            path: /

Sau khi tạo xong các file yaml, chúng ta vào terminal và chạy:

microk8s kubectl apply -f namespace.yaml
microk8s kubectl apply -f jenkins-pv.yaml
microk8s kubectl apply -f jenkins-pvc.yaml
microk8s kubectl apply -f deployment.yaml
microk8s kubectl apply -f ingress.yaml

Sau khi thực thi các lệnh trên, chúng ta mở Kubernetes Dashboard UI và kiểm tra các resource của namespace jenkins đã được khởi tạo thành công chưa. Nếu mọi thử ổn, bây giờ có thể truy cập vào jenkins master tại: http://jenkins.yourdomain.com

Cấu hình plugin Kubernetes cho Jenkins master

Truy cập vào phần http://jenkins.yourdomain.com/configureClouds/

Chúng ta cần cấu hình để Jenkins server có thể hoạt động được với Kubernetes cluster.

Thông tin Kubernetes URLKubernetes server certificate key được lấy từ output của lệnh microk8s config:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURBVENDQWVtZ0F3SUJBZ0lKQVBXUnJiZmtkR1cvTUEwR0NTcUdTSWIzRFFFQkN3VUFNQmN4RlRBVEJnTlYKQkFNTURERXdMakUxT.............XFFF
    server: https://xxx.xxx.xxx.xxx:xxxxx
  name: microk8s-cluster
.....

Linux agent

MacOs agent

Kết luận