# Deployment

## EC2 서버 배포

***

### EC2 IP 주소 확인

***

```bash
curl ident.me
```

```bash
xx.xxx.x.xxx
```

### EC2 셋팅

***

1. pemKey 이용해서 EC2 서버 들어가기<br>

   terminal

   ```bash
   ssh -i {yourkey}.pem {ubuntu@xxxx.xx.x.x.x}
   ```

   <br>
2. 방화벽 오픈
   * 기본적으로 방화벽이 설정돼있음
   * 필요한 포트번호 열기

     * https : 443, http: 80, ssh : 22/tcp
     * Jenkins: 8080, SpringBoot: 8081, mysql:3306

     ```bash
     sudo ufw allow <Port>
     ```
3. 방화벽 활성화

   ```bash
   sudo ufw enable
   ```
4. 방화벽 상태 확인

   ```bash
   sudo ufw status
   ```

### 도커 설정

***

1. 오래된 버전의 도커 삭제

   ```bash
   sudo apt-get remove docker docker-engine docker.io containerd runc
   ```
2. apt package update

   ```bash
   sudo apt-get update
   ```
3. 도커 설치를 위해 필요한 패키지 설치

   ```bash
   sudo apt-get install -y ca-certificates \
       curl \
       software-properties-common \
       apt-transport-https \
       gnupg \
       lsb-release
   ```
4. gpg Key 다운

   * 리눅스 패키지 툴이 프로그램 패키지가 유효한지 확인하기 위해 설치 전 gpg키를 통해 검증함

   ```bash
   sudo mkdir -p /etc/apt/keyrings
   ## Docker의 Official GPG Key 등록
   curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

   ## stable repository를 등록
   echo \
       "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
       $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
   ```
5. Docker Engine 설치

   ```bash
   sudo apt-get update
   sudo apt-get install docker-ce docker-ce-cli containerd.io
   ```
6. Docker 설치 확인

   ```bash
   docker --version
   ```

### 도커 설정

***

1. 사용자 권한 설정

   * 설정 후 재시작을 해야 적용됨

   ```bash
   sudo usermod -aG docker $USER
   ```
2. docker-compose 설치

   * docker-compose
     * 젠킨스 설치할 때 편하게 하기 위해 설치
     * 여러 개의 컨테이너로부터 이루어진 서비스를 구축, 실행하는 순서를 자동으로 하여, 관리를 간단히하는 기능

   ```bash
   #컴포즈 설치
   sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
   ##컴포즈 권한 설정
   sudo chmod +x /usr/local/bin/docker-compose
   ##컴포즈 설치 확인
   docker-compose --version
   ```

### 젠킨스 설치(도커 컨테이너) 및 계정 생성

***

1. 젠킨스 컨테이너 생성

   * docker-compose 이용
   * 도커에 젠킨스를 이미지를 이용하여 설치

   ```bash
   vim docker-compose.yml
   ```
2. 네트워크 생성

   * default 네트워크를 harunetwork로 설정
   * 이 네트워크로 컨테이너 간 통신을 한다.

   ```bash
   sudo docker network create harunetwork
   ```
3. docker-compose.yml 생성

   ```yaml
   version: "3.8"
   services:
           jenkins:
                   privileged: true
   								image: jenkins/jenkins:lts
                   container_name: jenkins
                   user: root
                   ports:
                           - "8080:8080"
                   volumes:
   												- /var/run/docker.sock:/var/run/docker.sock
   						            - /jenkins:/var/jenkins_home
                   environment:
                           TZ: "Asia/Seoul"
           nginx:
                   container_name: nginx
                   image: nginx:alpine
                   ports:
                           - "80:80"
                           - "443:443"
                   volumes:
                           - ./data/nginx:/etc/nginx/conf.d
                           - ./data/certbot/conf:/etc/letsencrypt
                           - ./data/certbot/www:/var/www/certbot
                           - ./nginx/var/www/dist:/var/www/dist
           certbot:
                   container_name: certbot
                   image: certbot/certbot
                   volumes:
                           - ./data/certbot/conf:/etc/letsencrypt
                           - ./data/certbot/www:/var/www/certbot
   networks:
           default:
                   name: harunetwork
   ```

   * jenkins의 home, docker.sock을 바인딩 시켜 젠킨스 컨테이너를 삭제해도 데이터는 남도록 한다.
   * jenkins는 8080포트를 받는다.
   * nginx의 포트 80, 443을 열어 http, https를 받을 수 있도록 한다.
   * nginx 컨테이너의 conf.d폴더, letsencrypt폴더, certbot폴더, dist폴더를 바인딩한다.
   * certbot 컨테이너의 letsencrypt폴더, certbot폴더를 바인딩한다. 이 때 nginx의 컨테이너의 letsencryt, certbot폴더와 같은 곳을 바인딩 시켜야 한다.
     * certbot : Let's Encrypt 인증서를 사용하여 자동으로 HTTPS를 활성화하는 무료 오픈 소스 소프트웨어 도구
   * services : 컨테이너 서비스
   * jenkins : 서비스 이름
   * image : 컨테이너 생성시 사용할 image, 여기서는 jenkins/jenkins:lts 이미지를 사용(jenkins의 lts버전을 가져온다는 뜻)
   * container\_name : 컨테이너 이름
   * volumes : 공유 폴더 느낌, aws의 /var/run/docker.sock와 컨테이너 내부의 /var/run/docker.sock를 연결, /jenkins 폴더와 /var/jenkins\_home 폴더를 연결.
   * ports : 포트 매핑, aws의 8080포트와 컨테이너의 8080 포트를 연결한다.
   * privileged : 컨테이너 시스템의 주요 자원에 연결할 수 있게 하는 것 기본적으로 False로 한다고 한다.
   * user : 젠킨스에 접속할 유저 계정 (root로 할 경우 관리자)
4. docker-compose.yml 실행

   ```yaml
   docker-compose up -d
   ```
5. 도커 컨테이너 확인

   ```bash
   sudo docker ps
   ```

### 젠킨스 생성

***

1. 젠킨스 확인

   ```bash
   http://{xxx.x.x.x.xx}:8080
   ```
2. password 확인

   ```bash
   sudo docker logs jenkins
   ```
3. 플러그인 설치
   * install suggested plugins 클릭
   * 기본 플러그인 자동 설치
   * select plugins to install : 사용자 지정 플러그인 설치

     <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FLsn6OjWRAtdepupOXiGv%2Fimage.png?alt=media&#x26;token=cbde336c-8418-474a-af0e-53e56ad1084e" alt=""><figcaption></figcaption></figure>
   * 설치중

     <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2F46FUfhPPEJvdiW8CA04J%2Fimage.png?alt=media&#x26;token=009bf6b9-8be7-4a58-84c6-0709af2820ac" alt=""><figcaption></figcaption></figure>
4. Admin User 생성

   * 계정명 : your id
   * 암호 : your password
   * 이름 : your name
   * 이메일 주소 : your email

   ### 젠킨스 설정

   1. Jenkins 관리 선택

      <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FbK89FjIsaHwrM0zaVnBt%2Fimage.png?alt=media&#x26;token=a162c00a-a643-43b7-b05c-8d45666d0871" alt=""><figcaption></figcaption></figure>
   2. 플러그인 관리

      <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FVCslGBrZRAfSw3siPKHm%2Fimage.png?alt=media&#x26;token=74f0b0b5-3232-4fa0-91ad-65f78cc8b951" alt=""><figcaption></figcaption></figure>
   3. 플러그인 설치
      * gitlab

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FylLe7pIDXxYghYN5YiG3%2Fimage.png?alt=media&#x26;token=6079f289-8b38-4a6e-a71b-4d46ea947d22" alt=""><figcaption></figcaption></figure>
      * docker

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FDfsnzvujZvHPszWnfqQs%2Fimage.png?alt=media&#x26;token=90940980-80f3-41cf-9cb8-a81ac7995a4a" alt=""><figcaption></figcaption></figure>
      * ssh

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FuVrhLUwOmpNDClFukdud%2Fimage.png?alt=media&#x26;token=db7f5215-1c26-4a48-bd0b-6cfe11d260d6" alt=""><figcaption></figcaption></figure>

   ### 젠킨스 프로젝트 생성 WebHook 설정, 자동 빌드 테스트

   1. 깃랩 Repo
   2. 젠킨스 프로젝트 생성
      * 새로운 Item 클릭

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FZiSgzN6cLs9d1RAPXPBy%2Fimage.png?alt=media&#x26;token=b75c163b-ad02-4b79-8754-d561dea2ddc5" alt=""><figcaption></figcaption></figure>
   3. 프로젝트 설정

      * freestyle project 클릭

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FppkbVPzn79dx7hy7GTbr%2Fimage.png?alt=media&#x26;token=04d922c9-8076-4d0d-9654-daebc2d85da4" alt=""><figcaption></figcaption></figure>
      * 깃랩 url 입력

        → 에러 메시지가 나타나는게 정상!!

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FwISank2GwoSuksf30zJH%2Fimage.png?alt=media&#x26;token=3e07d0f3-aa00-40dd-a665-8168274c8bdd" alt=""><figcaption></figcaption></figure>
      * jenkins 추가
        \*

        ```
        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FwmCIpQTy4zmj1ZfMwhra%2Fimage.png?alt=media&#x26;token=99a7b0dc-5afc-4085-88b6-223a6e69d909" alt=""><figcaption></figcaption></figure>
        ```

        * Username : 깃랩 아이디
        * Password : 깃랩 비밀번호
        * ID : Credential 구별할 아무 텍스트 입력하면 됩니다.
      * Credential 추가

        → 오류 메시지 사라지면 성공!

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2Fzi94L5mhQVJSIbavm82q%2Fimage.png?alt=media&#x26;token=c18a0c28-aa18-4c94-8f81-8449e1484842" alt=""><figcaption></figcaption></figure>
      * MR 시 빌드 될 브랜치 설정

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FbInc84guK33o4cEFRLXX%2Fimage.png?alt=media&#x26;token=3978001f-ca5d-48fd-891d-2e79f3e71640" alt=""><figcaption></figcaption></figure>
      * 빌드 설정

        * 프로젝트 merge시 자동 빌드

          <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2F297Ay3h9cfFOn6ZKy5FG%2Fimage.png?alt=media&#x26;token=68ccd5d8-0be0-4d8f-86ee-8f1aaf36bb6f" alt=""><figcaption></figcaption></figure>
        * 고급 클릭 - secret token 생성
        *

        <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FsJUpkBehwF39hrZhqC0h%2Fimage.png?alt=media&#x26;token=33ec513f-00b0-4b96-b3f5-a6d6f6fd5e45" alt=""><figcaption></figcaption></figure>

        ```bash
         
         # Secret Token
        //your secret token
         
        ```

        * build step - execute shell 추가

          → 연결 테스트를 위한 pwd 명령어 입력(추후 수정)

          <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FshIlLKrNXXoZEjxbL2M7%2Fimage.png?alt=media&#x26;token=024eef93-e46a-4dd8-b6e8-3dc5abf7032a" alt=""><figcaption></figcaption></figure>

      ### 깃랩 WebHook 연결

      1. 깃랩 Settings - Webhooks

         <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2F32gUvLUYVSISafvPfI6I%2Fimage.png?alt=media&#x26;token=0d293b4d-e0ca-447a-a7da-28b7192f7e16" alt=""><figcaption></figcaption></figure>
      2. 정보 입력

   ### 젠킨스와 연결된 gitlab 프로젝트로 도커 이미지 빌드

   1. 젠킨스 커네이너 안에 도커 설치

      * 젠킨스에서 도커 빌드를 하기 위함

      ```bash
      sudo docker exec -it jenkins bash
      ```
   2. docker 사전 패키지 설치

      ```bash
      apt update
      apt-get install -y ca-certificates \
          curl \
          software-properties-common \
          apt-transport-https \
          gnupg \
          lsb-release
      ```

      * 루트계정으로 접속되어있기 때문에, 젠킨스 컨테이너 내부에서는 명령어에 sudo를 지움
   3. gpg 키 다운로드

      ```bash
      mkdir -p /etc/apt/keyrings
      curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg

      echo \
          "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
          $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
      ```
   4. 젠킨스 컨테이너 내부에 설치된 os 확인

      ```bash
      cat /etc/issue
      ```

      * OS : debian
      * 기존 제공 방식은 ubuntu에 대한 gpg키를 다운로드 하는것이기 때문에 debian으로 바꿔야함
      * 바꾸지 않으면 패키지를 못찾음
      * 기존 명령어에서 ubuntu로 되어있는 부분을 debian으로 바꾸어주면 됨
   5. Docker 설치

      ```bash
      apt update
      apt install docker-ce docker-ce-cli containerd.io docker-compose
      ```

      * Jenkins Container에 Docker 설치 완료!
   6. 프로젝트에 DockerFile 작성

      1. SpringBoot DockerFile

      ```docker
      FROM openjdk:11
      COPY /build/libs/api-0.0.1-SNAPSHOT.jar app.jar
      COPY /src/main/resources/application.yml application.yml
      EXPOSE 8081
      ENTRYPOINT ["java", "-jar", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=prod", "-Dspring.config.location=/application.yml,/home/ubuntu/properties/application-db.yml,/home/ubuntu/properties/application-aws.yml,/home/ubuntu/properties/application-secret.yml", "app.jar"]
      ```

      * classpath 인식 안되어 application.yml을 스프링이 읽지 못했음 → application.yml 을 컨테이너에 직접 복사 후 사용함

      b. React Project DockerFile

      \*\*\* **경로 수정하기**

      ```docker
      FROM node:16.17.0 as build-stage
      WORKDIR /var/jenkins_home/workspace/deploytest/testproject_react
      COPY package*.json ./
      RUN npm install
      COPY . .
      RUN npm run build
      FROM nginx:stable-alpine as production-stage

      COPY --from=build-stage /var/jenkins_home/workspace/deploytest/testproject_react/build /usr/share/nginx/html
      #COPY --from=build-stage /var/jenkins_home/workspace/deploytest/testproject_react/deploy_conf/nginx.conf /etc/nginx/conf.d/default.conf
      EXPOSE 80
      CMD ["nginx", "-g","daemon off;"]
      ```

### 젠킨스에서 DockerFile 이용 도커 이미지 생성(Backend)

***

1. Jenkins 관리 클릭

   <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FVupbULAhUwVMp30VO0It%2Fimage.png?alt=media&#x26;token=5d025fc6-b0e2-4d34-8054-2c22483254f0" alt=""><figcaption></figcaption></figure>
2. Global Tool Configuration 클릭
3. Gradle 추가
4. 젠킨스 프로젝트 페이지에서 구성 버튼 클릭
5. Build Steps 수정

   \*\* 순서 중요!!!

   ```bash
   # 도커 시작 전, 기존에 실행중인 도커를 멈추고 제거하는 작업.
   docker ps -f name=frontend -q | xargs --no-run-if-empty docker container stop

   # 컨테이너 제거
   docker container ls -a -f name=frontend -q | xargs -r docker container rm

   # frontend 도커 이미지 생성
   docker build -t frontend:latest ./frontend

   # frontend 도커 컨테이너 실행 
   docker run -d --name frontend -p 80:80 -p 443:443 -v /etc/letsencrypt/:/etc/letsencrypt/ -v /etc/localtime:/etc/localtime:ro --network idontknownetwork frontend:latest
   ```

   <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2Fndm0ZbEyPBkeYZplyUA7%2F%25E1C92~1.PNG?alt=media&#x26;token=96f54de8-2063-4c12-9250-35a3af2d9ec9" alt=""><figcaption></figcaption></figure>
6. 빌드 성공
7. tar파일 생성 확인
   * 젠킨스에서 도커 이미지 빌드 후 tar 압축파일로 생성 완료!

***

* Dockerfile 이미지 빌드 전 스프링 프로젝트 빌드 필요!!

### 빌드한 도커 이미지를 베이스로 컨테이너 생성(기본 배포 완료)

***

1. Jenkins 관리 선택
2. 시스템 설정 클릭
3. Publish over ssh - ssh servers 추가
   * Name : 그냥 이름
   * Hostname : EC2 IP
   * Username : EC2 접속 계정 이름
   * Key : EC2 에서 생성했던 pem파일(VSCode로 오픈 후 복붙)
4. Test Configuration 클릭
5. 컨테이너 확인
   * backend 컨테이너가 추가됨

### 컨테이너간 서버 통신을 위한 네트워크 설치

***

1. 네트워크 설치

```bash
sudo docker network create harunetwork
```

## EC2서버에 mysql 설치

***

1. docker-compose.mysql.yml 생성

   ```bash
   sudo vi docker-compose.mysql.yml
   ```

   ```yaml
   version: '3'
     services:
       mysql:
         image: mysql:8.0
         container_name: mysql
         ports:
           - 3306:3306 # HOST:CONTAINER
         environment:
           MYSQL_DATABASE: haru
           MYSQL_ROOT_PASSWORD: password
           MYSQL_USER: develop
           MYSQL_PASSWORD: password
           TZ: Asia/Seoul
         command:
           - --character-set-server=utf8mb4
           - --collation-server=utf8mb4_unicode_ci
         volumes:
           - ./mysql/data:/var/lib/mysql
         networks:
           - harunetwork
     - 
     networks:
       idontknownetwork:
         external: true
   ```

   1. 실행

   ```bash
   docker-compose -f docker-compose.mysql.yml up -d
   ```

   1. 확인

   ```bash
   docker ps -a
   ```

   mysql container 실행중!!

### **Docker-compose + Nginx SSL 적용하기 (certbot)**

### nginx 설정

***

### SSL 인증서 발급

***

1. certbot 설치

   ```bash
   sudo snap install certbot --classic
   ```

   ```bash
   certbot certonly --standalone -d k7a204.p.ssafy.io
   ```

   * nginx 컨테이너에서 80포트를 사용중이어서 컨테이너 중지!

   ```bash
   docker stop nginx
   ```
2. 재설치
3. 인증서 경로 확인

   ```bash
   Certificate is saved at: /etc/letsencrypt/live/k7a204.p.ssafy.io/fullchain.pem
   Key is saved at:         /etc/letsencrypt/live/k7a204.p.ssafy.io/privkey.pem
   ```
4. nginx container 볼륨 설정

   * ec2서버 경로에 저장된 인증서를 nginx container 안에 넣어줘야 함

     <figure><img src="https://2508988307-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOSeOeSHdBrqt2ofHCoto%2Fuploads%2FzwcPvk0IRWS7MKLcI4En%2FUntitled%2015.png?alt=media&#x26;token=fa712685-4269-40da-acc2-445d3e678cf4" alt=""><figcaption></figcaption></figure>

   ```bash
   vi docker-compose.yml
   ```
5. nginx 이미지 다시 올리기

   ```bash
   docker-compose up -d nginx
   ```
6. 컨테이너 확인

   ```bash
   docker ps -a
   ```
7. 확인

***
