2021년 08월 31일 TIL

5 minute read

오늘은 이전 O-GYM 프로젝트의 배포에 대해 팀원과 함께 문서화 작업을 했다. 첫 배포였기에 굉장히 많은 시행착오를 겪은 과정이었지만, 그럼에도 즐거운 과정이었다고 생각한다.

✔ 배포 문서 ✔

Date : 2021-08-31

목차

  1. Setting

  2. Issue & Prerequisites

  3. 배포 준비 과정

Setting

  1. microk8s 공식문서

  2. Docker, cri-o Docker 공식문서 Cri-o 공식문서

  3. Jenkins Jenkins 공식문서

  4. ArgoCD ArgoCD 공식문서

  5. prometheus, Grafana Prometheus 공식문서 Grafana 공식문서

Issue&Prerequisites

  • 데이터베이스 덤프 파일
    • data.sql, schema.sql을 통해 실행하면 자동으로 생성됩니다!
  1. Jenkins가 GitLab에서 코드를 가져오기 위한 설정

  2. Jenkins Pipeline 내 Docker Hub에 접속해서 만들어진 이미지를 Push

  3. 이미지를 통해서 만들어진 리소스 yaml 파일들을 Github에 push

    • 원래는 public repo 였으나, AWS S3 보안 키 issue

      Email 과 같은 문제가 발생

    • Private Repo에서 git 코드에 ACCESS 할 수 있는 ssh 설정 필요

  4. kubectl을 이용해 이미지에서 리소스 파일 추출

    • kubectl 명령어 사용이 필수

      • microk8s를 snap 명령어로 install 후 microk8s kubectl 처럼 사용이 가능
     ## 예시 
     microk8s kubectl get pods 
    

배포 준비 과정

  1. GitLab에서 Jenkins로 코드를 보내주기 위한 설정

    1. GitLab WebHook 생성

    2. Jenkins 환경설정에서 GitLab 정보 등록

  2. Jenkins Pipeline 작성

Jenkins Pipeline에서 작성 시 주의사항

  • openjdk-11, gradle 직접 설정

    • jenkins 내 Global Tool Configuration

      • Gradle, JDK 설정을 해주어야 합니다

        • java는 다른 버전을 지원하지 않아 adoptopenjdk.net에서 받아서 사용

        • Gradle은 7.1.1 버전을 사용합니다

      • Github Authenticaiton이 8월 13일 자 이후로, password

// 저희 pipeline 구성 코드입니다 
pipeline {
    agent any
    tools {
        jdk("openjdk-11")
        gradle "test_gradle"
    }
    stages {
        
        stage('Git clone') {
            steps {
                git branch: 'release', url: 'https://[아이디]:[비번]@lab.ssafy.com/s05-webmobile1-sub3/S05P13B305.git'
            }
        }
        stage('Gradle version') {
            steps {
                sh '''gradle --version 
                echo $JAVA_HOME
                docker version
                '''
            }
        }
        stage('Gradle') {
            steps {
                sh '''
                cd ./BackEnd
                echo ">> project Build Start"
                chmod +x gradlew
                ./gradlew build --no-daemon --stacktrace --exclude-task test
                ''' 
            }
        }
        stage('JAR Make Test') {
            steps {
                sh '''
                    cd ./BackEnd
                    echo ">> pwd"
                    pwd
                    echo ">> go jar"
                    cd ./build/libs
                    
                    JAR_NAME=ogym-0.0.1-SNAPSHOT.jar
                '''
            }
            
        }
        stage('Make Image') {
            steps{
                writeFile file:'Dockerfile', text: '''FROM adoptopenjdk/openjdk11:latest
ARG JAR_FILE=BackEnd/build/libs/ogym-0.0.1-SNAPSHOT.jar
EXPOSE 8081
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar","/app.jar", "--spring.profiles.active=prod"]
                '''
                sh ''' 
                docker login -u 39ghwjd -p !!95dlfwls
                docker build -t 39ghwjd/demo_backend .
                docker push 39ghwjd/demo_backend:latest
                '''
                
            }
        }
        stage('Make yaml in kubectl'){
            steps {
                sh '''
                    mkdir -p BackEnd/deploy
                    kubectl create deployment demobackend --image=39ghwjd/demo_backend:latest --dry-run -o=yaml> BackEnd/deploy/deployment_backend.yaml
                    echo --- >> BackEnd/deploy/deployment_backend.yaml
                    kubectl create service clusterip demobackendservice --tcp=8081:8081 --dry-run -o=yaml | kubectl set selector --local -f - 'app=demobackend' -o=yaml >> BackEnd/deploy/deployment_backend.yaml
                    cat BackEnd/deploy/deployment_backend.yaml
                '''
            }
        }
        stage('FrontEnd'){
            steps {
                sh '''
                    cd ./FrontEnd 
                    docker build -t 39ghwjd/demo_frontend .
                    docker push 39ghwjd/demo_frontend:latest
                '''
            }
        }
        stage('Make frontEnd yaml in kubectl'){
            steps {
                sh '''
                    mkdir -p FrontEnd/deploy
                    kubectl create deployment demofrontend --image=39ghwjd/demo_frontend:latest --dry-run -o=yaml > FrontEnd/deploy/deployment_frontend.yaml
                    echo --- >> FrontEnd/deploy/deployment_frontend.yaml
                    kubectl create service clusterip demofrontendservice --tcp=80:80 --dry-run -o=yaml | kubectl set selector --local -f - 'app=demofrontend' -o yaml >> FrontEnd/deploy/deployment_frontend.yaml
                    cat FrontEnd/deploy/deployment_frontend.yaml
                '''
            }
        }
        stage('Deploy GitHub'){
            steps {
               withCredentials([string(credentialsId: 'IMHOJEONG', variable: 'TOKEN')]) {
                    sh '''
                    git config user.email 39ghwjd@naver.com
                    git config user.name IMHOJEONG
                    mkdir -p deploy
                    cd ./BackEnd/deploy
                    cp deployment_backend.yaml ../../deploy/deployment_backend.yaml
                    cd ../../FrontEnd/deploy
                    cp deployment_frontend.yaml ../../deploy/deployment_frontend.yaml
                    cd ../../deploy/
                    cat deployment_backend.yaml >> deployment.yaml
                    rm -rf deployment_backend.yaml
                    echo --- >> deployment.yaml
                    cat deployment_frontend.yaml >> deployment.yaml
                    rm -rf deployment_frontend.yaml
                    git add .
                    git commit -m 'Triggered Build: ${env.BUILD_NUMBER}'
                    git push -f https://IMHOJEONG:$TOKEN@github.com/IMHOJEONG/GitOps_Project.git
                    '''
	 }
            }
        } 
    }
}
  1. microk8s 구성
  • microk8s enable 명령어로 필요한 addon들 추가

    • ingress, metallb, metrics-server, prometheus
  • microk8s kubectl 명령어, yaml 파일 설정으로 리소스 customize 필수

    • 리소스 yaml 파일 작성 후, microk8s kubectl apply -f ~~~.yaml로 설치

    • metallb 구성 시, ec2 private ip를 loadbalancer ip로 작성 해야 로드밸런서가 처리할 수 있게 됨

### ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: http-ingress
spec:
  tls:
  - hosts:
    - i5b305.p.ssafy.io
    secretName: i5b305-p-ssafy-io
  rules:
  - host: i5b305.p.ssafy.io
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: demofrontendservice
            port:
              number: 80
      - pathType: Prefix
        path: /api
        backend:
          service:
            name: demobackendservice
            port:
              number: 8081
      - pathType: Prefix
        path: /test
        backend:
          service:
            name: web
            port:
              number: 8080

### ingress-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: ingress
  namespace: ingress
spec:
  selector:
    name: nginx-ingress-microk8s
  type: LoadBalancer
  # loadBalancerIP is optional. MetalLB will automatically allocate an IP
  # from its pool if not specified. You can also specify one manually.
  # loadBalancerIP: x.y.z.a
  loadBalancerIP: 172.26.8.91 ## EC2 Private IP!
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
    - name: https
      protocol: TCP
      port: 443
      targetPort: 443

  • mysql pod, statefulset 구성
### mysql-storageclass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: manual
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard

### mysql-pv 구성 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

### mysql-deployment 구성 
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - protocol: TCP
    port: 3306
    nodePort: 30036
    targetPort: 3306
  selector:
    app: mysql
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:8.0.26
        name: mysql
        env:
          # Use secret in real usage
        - name: MYSQL_ROOT_PASSWORD
          value: root
        - name: MYSQL_ROOT_HOST
          value: '%'
        - name: MYSQL_USER
          value: i5b305
        - name: MYSQL_PASSWORD
          value: 1q2w3e4r
        - name: TZ
          value: Asia/Seoul
        - name: MYSQL_HOST
          value: '%'
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
  • openvidu 설정 : on-premise

  • https 통신을 위한 인증서 발급 방법

    • ec2에 nginx를 직접 설치 후, 인증서를 발급 받음

    • 그 후에, 올라가 있던 nginx service stop하고, ingress에 tls 인증서를 추가해 주면 됨

    • 인증서 방식은 letsencrypt로 certbot을 이용해 발급 받는다

    • 대신, openvidu에서는 이미 발급된 인증서 기반으로 사용해야 하기 때문에 owncert로 설정을 바꾸어 사용해준다.

  1. argocd 구성
  • ssh을 이용하는 repo를 생성

  • ec2 내 ssh 키를 발급받고 github private repo에 public key, kubernetes pod를 올린 argocd 내부에서 private key를 넣어서 생성

  • 그 후, 인식하고, auto-sync enable로 github의 코드가 변경될 시, 리소스를 새로 만들어주게 구성

  1. redis, openvidu, jenkins는 docker로 -p 옵션을 주어 포트포워딩을 해서 올림

    • jenkins는 -v 옵션으로 볼륨 마운트를 통해 파이프라인 내부에서 docker 명령어를 사용할 수 있게 해주어야 함

Categories:

Updated: