Travis CI 배포 자동화

Zerodin·2021년 11월 17일
1
post-thumbnail
post-custom-banner

CI & CD

일단 어원에 대한 간단한 설명을 하자면,
CI(Continuous Integration/지속적 통합) & CD(continuous Deployment/지속적인 배포)라고 한다.

즉, VCS 시스템(코드 형상관리)에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정(CI)과 빌드결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정(CD)을 뜻한다.

이러한 CI&CD가 등장하게된 이유로는 개발자가 순수하게 개발에만 집중을 하기 위한 병합 및 배포를 담당해 줄 무엇인가가 필요해졌기 때문이다.

하지만 CI를 단순히 도입했다고 해서 끝이 아니다.
책에서는 마틴 파울러의 블로그를 예로 들어 4가지 규칙을 언급했다.

CI를 도입할 때 4가지 규칙.

  • 모든 소스 코드가 살아 있고(현재 실행) 누구든 현재의 소스에 접근할 수 있는 단일 지점을 유지할 것.
  • 빌드 프로세스를 자동화해서 누구든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것.
  • 테스팅을 자동화해서 단일 명령어로 언제든지 시스템에 대한 건전한 테스트 수트를 실행할 수 있게 할 것.
  • 누구나 현재 실행 파일을 얻으면 지금까지 가장 완전한 실행 파일을 얻었다는 확신을 하게 할 것.

이중에서 특히 중요한 포인트는 테스트의 자동화다.
우리가 테스트코드를 작성함으로써 얻는 안정성을 근거로 새로운 빌드를 계속 업데이트 하는 것이 가장 주요하다고 책에서는 언급하고 있다.

Travis CI 연동하기

내가 사용할 CI로는 Github에서 무료로 제공하는 Travis CI다.
왜 jenkins를 사용하지 않고 Travis를 사용하는 것일까?

나는 지금 AWS에서 EC2서버를 한대 사용하고 있고 요금제는 무료버전을 사용중이다.
이 무료 요금은 서버 한대만을 기준으로 제공해주는데 jenkins을 사용하려면 인스턴스를 추가해야 한다.(비용이 발생한다.)

그래서 오픈소스 웹서비스인 Travis CI를 책에서 권하고 있다.

Travis CI 웹서비스 설정

책에 나온데로 https://travis-ci.org/로 접근해보니 https://app.travis-ci.com/로 가라고 한다.
새로운 url로 가서 git 계정으로 연동을 하자.
그리고 연동계정의 메일로 접속해 인증처리를 해주자.

책에서는 저장소 활성화를 하라고 하는데 UI가 너무 많이 달라져서 난감하다.
일단 되는데로 진행해보도록 하자.

연동해서 로그인 한 다음, setting으로 들어가 보자.


사용 요금제 안내가 나온다. 일단 무료를 선택하겠다.
개인정보와 카드정보를 입력해준다.

설치 안내 화면이 나왔다. 설치를 하도록 하자.

설치후 내 git repository들이 쭉 나온다.
여기서 지금 진행중인 aws 프로젝트의 setting에 접근하자.

setting을 확인해보니 기본적인 상태에서 별다르게 건드릴것은 없어보인다.

프로젝트 설정

Travis CI의 상세한 설정은 프로젝트에서 작성한 .travis.yml파일로 한다.
생성위치는 bundle.gradle과 같은 곳에서 하면 된다.

브랜치에서 생성한 yml파일을 push후 PR을 완료했다.
이제 다시 travis에 가서 build history를 확인해보자.

에러가 발생했다.

에러 발생에 대한 메일도 같이 왔다.

원인을 찾아보자.

/home/travis/.travis/functions: line 351: ./gradlew: Permission denied
권한 문제로 보인다.
yml 내용중에 script: "./gradlew clean build" 이 부분을 실행하는 라인에서 발생했다.
해당 라인 뒤에 권한을 주는 내용을 추가한다.
before_install:
chmod +x gradlew

다시 PR을 하고 잠시 기다리니 travis가 반응을 하기 시작했다.
결과는 성공.

그런데 꼭 저렇게 yml에 추가를 해야 하는 방법만 있는걸까?
구글링을 잠시 해봤다.
그리고 다른 방법 한가지를 더 알아 냈다.
git명령어를 통해서 권한을 주는 방법이 있었다.

git update-index --chmod=+x gradlew
로컬PC 터미널에서 해당 명령어를 수행 후 commit & push를 했다.
그리고 리모트 branch에서 master로 PR을 작업해 주었다.
결과는 성공이였다.
불필요하게 설정에서 권한을 사용하지 않고 git 커맨드를 활용해보로독 하자.

Travis CI와 AWS S3 연동하기

이제 정적 소스를 관리하기 위한 파일서버를 연동해야 한다.
내가 연동할 amazon S3 서버는 스토리지 서버의 종류로써 파일서버 역할을 수행할 것 이다.

책에서 그리는 전체적인 시스템의 연동 구조는 아래와 같다.

Amazon CodeDeploy에 전달할 jar를 생성하기 위해 S3와 Travis 연동부터 시작하자.

빌드와 배포를 분리하는 이유

책에서는 CodeDepoly의 빌드와 배포 기능을 전부 사용하지 않기를 권하고 있다.
빌드의 역할과 배포의 역할을 각각 분리함으로써 배포나 빌드만 필요한 경우 하나의 행위만을 하도록 하기 위함이라고 명시하고 있다.

AWS key 발급(IAM 서비스)

AWS 서비스를 외부에서 접근하기 위해서는 접근 가능한 권한이 필요한데 이를 증명해주는 키를 발급 받아야 한다.
amazon에서는 이러한 인증 관련 기능을 제공하는 서비스로 IAM(Identity and Access Management)를 제공하고 있다.


사용자를 추가하자.

권한을 추가해야 한다.
우선 검색어로 s3full로 검색해서 나오는 권한을 선택하자.

그리고 다음으로 codedeployfull로 검색해서 나오는 권한을 추가로 선택하자.

다음은 간단한 테그 정보를 입력하자.

검토화면에서 이렇게 나와야 한다.

생성하면 아래와 같이 엑세스키와 비밀 엑세스키가 발급된다.

이제 Travis CI에 로그인하고 setting에서 발급받은 키들을 각각 등록하도록하자.

등록을 하고나면 .travis.yml에서 $AWS_ACCESS_KEY, $AWS_SECRET_KEY로 호출해서 사용이 가능해진다.

S3버킷 생성

이제 S3 메뉴에 접근하자.

버킷 만들기를 시작하자.

설정내용중 주의 깊게 확인해야 할 부분은 버킷의 퍼블릭 액세서 차단 설정이다.
이 내용은 우리가 이제 S3로 만들어서 저장할 Jar파일에 대한 퍼블릭 접근을 제한한다는 의미로써 Jar를 아무나 접근해서 다운받아 해당 어플리케이션의 주요 설정정보를 탈취당할 수 있기 때문에 반드시 모든 퍼블릭 액세스 차단을 설정하도록 하자.

생성하면 다음과 같이 버킷이 목록에 추가된다.

.travis.yml 추가

이제 travis에서 빌드하여 만든 Jar 파일을 S3에 올릴 수 있도록 설정을 추가하자.

branch에 push후 PR을 진행하면 자동으로 Travis에서 빌드를 진행한다.
아래와 같이 메세지가 출력되면 성공이다.

S3에서 업로드된 파일을 확인해보자.

정상적으로 업로드가 되었다.

Travis CI와 AWS S3, CodeDeploy 연동하기

이제 AWS CodeDeploy를 이용하기 전에 배포 상대인 EC2가 CodeDeploy와 연동 받을 수 있도록 IAM에서 역할을 생성하도록 하자.

EC2에 IAM 역할 추가

IAM 콘솔화면에서 역할을 선택하자.

역할 만들기를 클릭해서 생성을 시작하자.


AWS 서비스 선택을 하고 일반 사용사례에서 EC2를 선택하고 다음 단계로 넘어가자.


AmazonEC2RoleforAWS-CodeDeploy를 선택하자.
권한 경계 설정은 일단 기본으로 선택된 상태로 넘어갔다.


간단한 테그를 작성하고 넘어간다.


역할이름을 작성해 준 다음 역할 만들기를 클릭한다.

이제 생성된 역할을 EC2에 적용해야 한다.
EC2 콘솔 화면으로 넘어가서 인스턴스 설정 > IAM 역할 수정을 선택하자.

아까 작성한 역할을 선택해준다.

이제 EC2 인스턴스를 재부팅해주면 된다.

CodeDeploy 에이전트 설치

EC2에 접속해서 다음 명령어를 입력하자.

  • 1 aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2
    다운로드가 정상적으로 이루어지면 아래같은 메세지가 나온다.
  • 2 실행권한을 부여하자.
    chmod +x ./install
  • 3 파일을 설치해야 한다.
    sudo ./install auto
  • 4 설치된 agent가 정상적으로 작동하는지 확인한다.
    sudo service codedeploy-agent status
    정상적으로 설치되었다면 PID가 할당되서 다음과 같은 메세지가 나온다.

위의 방법은 책에서 소개하는 방식이다.

다음은 AWS 공식문서 가이드 내용이다.
나는 이 방식으로 설치를 했다.

안내되는 순서대로 진행해보자.
yum update를 진행하고 wget와 ruby를 설치해주자.
그리고 CodeDeploy agent를 설치하기 위해 내 EC2의 버킷명과 리전 식별자를 넣은 아래 명령어를 작성해야 한다.
자신이 사용하는 버킷과 리전에 따라 작성해야 한다.
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install

여기서 리전버킷과 리전식별자는 안내되는 별도의 페이지에서 확인한 값을 사용해야 한다.
(참고 :https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names)

정상적으로 다운로드가 되었다면 다음이어서 인스톨을 하자.

정상적으로 인스톨이 되었는지 확인을 위해 아래 명령어를 실행해보자.
sudo service codedeploy-agent status

정상적으로 설치가 되고 실행이 된 것으로 보인다.

CodeDeploy를 위한 권한 생성

이번에는 IAM 메뉴에서 CodeDeploy의 역할을 생성하고 권한을 부여해야 한다.
IAM 콘솔 메뉴에서 역할메뉴를 선택하고 아래와 같이 설정하자.

권한정책은 한개뿐이다. 다음 단계로 넘어가자.

태그 내용을 간략히 작성하자.

역할이름을 작성하고 만들면 끝이다.

CodeDeploy 생성

AWS에서 제공하느 배포 관련 서비스 3가지가 있다.

  • Code Commit : AWS에서 지원하는 원격 저장소. 프라이빗 기능을 지원함.
  • Code Build : AWS에서 지원하는 빌드용 서비스. 멀티 모듈을 배포시 쓸만함.
  • Code Deploy : AWs에서 지원하는 배포 서비스. 오토 스케일링 그룹 배포, 블루 그린 배포, 롤링 배포, EC2 단독 배포 등 많은 기능을 지원.

여기서 우리는 Code Deploy이만 사용하는 것이다.
(나머지 서비스는 타 서비스들이 이미 너무 쟁쟁하게 많이 쓰이고 있다.)

작업 순서로는
1. 배포 어플리캐이션을 생성한다.
2. 배포 그룹을 생성한다.
3. 배포 설정을 한다.

Code Deploy 서비스 화면으로 가서 어플리캐이션을 생성하자.

어플리케이션 명을 작성하고 플랫폼을 EC2/온프레미스로 선택해준다.

배포 그룹을 생성하겠다.

배포 그룹 생성 버튼을 클릭하자.

배포 그룹 이름을 작성하고 서비스 역할은 기존에 등록된 것을 선택해준다.

배포 유형은 현재 위치로 설정하고 환경구성에서는 Amazon EC2 인스턴스를 체크한다.
태그 그룹도 일전에 작성한 값들을 넣어주자.

배포 설정은 아래와 같이 설정해준다.
로드 밸런서는 체크를 해제하도록 하자.

TravisCI, S3, CodeDeploy 연동

이제 S3에 넘겨줄 zip파일을 저장할 디렉토리를 생성해야 한다.

mkdir ~/app/step2 && mkdir ~/app/step2/zip

프로세스의 흐름을 간단히 집어보면
1. Travis CI에서 build.
2. build 종료 후 S3로 zip파일 전송.
3. zip파일을 home/ec2-user//app/step2/zip/ 으로 복사 후 압축해제.

이를 위해서는 Travis CI와 AWS CodeDepoly에서 각각의 설정을 요구하는데,
기존의.travis.yml 과 appspec.yml을 새로 생성해서 진행한다.

appspec.yml 신규내용.

.travis.yml 추가내용.(deploy 항목에 codedeploy 내용 추가)

작성이 완료되면 commit & push를 진행하고 PR을 통해서 master 에 merge하자.

Traive CI가 정상적으로 작동했는지 확인을 해야 한다.

성공이다.

그럼 S3에가서 새로 파일을 생성했는지 생성시간을 확인해보자.

11.15에 생성했었는데 반영일인 16일로 갱신되었다.

그렇다면 아까 EC2에서 생성한 디렉토리로 파일이 전송되었는지를 확인해보자.

잘 생성되었다.

이로써 Travis CI & S3 & CodeDeploy 가 연동이 성공했다.

배포 자동화 구성

이제 deploy.sh을 수정해서 Jar가 배포되도록 해보자.

별도의 디랙토리를 생성하고 쉘스크립트를 작성하겠다.

scripts/deploy.sh

step1에서 작성했던 내용에서 git pull을 통한 직접적인 빌드관련 부분을 제거했다.
그리고 실행권한에 대한 내용이 추가되었다.

수정내용은 현재 Zip파일을 생성할때는 모든 파일이 대상이다.
이 대상을 선별하려고 한다.
선별 대상 내역은 Jar, appspec.yml, 배포를 위한 스크립트 이다.

.traivs.yml에 before_deploy 내용을 수정하자.


여기서 한가지 중요한점이 있다.
변경된 before_deploy의 내용을 보면 압축을 시킬 대상의 파일들을 before-deploy이라는 디랙토리로 보낸다음 해당 디랙토리내용을 전부 압축하는 방식으로 진행하고 있다.
왜 이렇게 파일을 선별해서 특정 디렉토리로 모으는것인가?
이유는 Travis CI 때문이다. 특정파일만을 선택해서 압축하는 기능이 없기 때문에 대상들을 선별해서 특정한 위치로 모으고 그 위치의 모든 파일을 압축하는 방식으로 해결하고 있다.

appspec.yml도 수정해야 한다.


수정된 내용을 살펴보자.
우선 권한에 대한 설정이 추가 되었다.
CodeDeploy에서 EC2서버로 보내지는 파일들을 ec2-user 권한을 가지도록 설정해야 한다.
그리고 hooks라는 내용이 추가되었다.
CodeDeploy 배포 단계에서 실행할 명령어들을 지정하는 부분인데 ApplicationStart 단계에서 ec2-user 권한으로 실행을 하도록 구성되었다.
그리고 스크립트의 실행시간 제한이 설정되었다.
이는 무한정으로 실행이 늘어지는 것을 방지하기 위해서 필요하다.

이제 작성된 내용들을 commit & push해서 PR을 하도록 하자.

Travis CI에서 빌드 상태를 확인해봤다.

성공이 떨어졌다.

S3에 생성된 파일이 갱신되었는지 확인해보자.

역시 갱신되었다.

실제 배포 과정 검증

이제 실제로 소스가 수정되면 배포가 진행되는지를 확인해 보자.
간단하게 index.mustache에서 텍스트 수정을 해보겠다.

스프링부트로 시작하는 웹 서비스 Ver.2에서 버전을 2.1로 수정해서 반영해보자.

S3까지는 정상적으로 배포가 잘되었다.
하지만 EC2에서 빌드하면서 오류가 발생했다.

step1에서 반영되서 작동중인 어플리캐이션이 8080 포트로 이미 구동중인 상태였다.
해당 실행 deploy.sh에서 경로를 step1로 이미 잡고 실행한 상태였다.
그런데 step2를 경로로 잡고 배포한 어플리캐이션이 실행되면서 기존에 step1로 실행된 어플리캐이션의 8080포트를 사용하는 어플리캐이션과 포트 충돌이 발생한 것으로 확인되었다.

책에서는 기존 사용중인 어플리캐이션의 종료에 대한 언급이 없어서 미쳐 생각치 못하고 진행하다 발생한 에러였다.

pid를 찾아서 step1쪽 어플리캐이션을 중단할까 했지만 우선 인스턴스 재부팅을 하는 쪽으로 방향을 잡았다.

인스턴스 재부팅이 끝난 뒤에 정상적으로 사이트가 접근되는 것을 확인했다.
간단하게 bundle.gardle 에서 스냅샷 버전을 1.0.1로 수정한 다음 다시 반영을 해보았다.

배포 전 화면

배포 후 화면

수정 내역이 제대로 반영되었다.

CodeDeploy 로그 확인

방금과 같이 에러가 발생하면 원인을 찾기 위해 에러로그를 확인해야 한다.
나는 급한 마음에 EC2서버에 접근해서 nohup.out을 통해서 에러를 확인했었다.

CodeDeploy에서도 배포시 발생하는 에러에 대한 로그확인이 가능하다.

cd /opt/codedeploy-agent/deployment-root

로 접근 한다음 ll을 이용해서 확인해보면

deployment-logs 파일을 통해 로그를 확인할 수 있다.

마무리

장작 3일간에 걸쳐서 Travis CI, S3, CodeDeploy 연동을 구축해보았다.
인프라 구축은 확실히 시간도 많이 들고 어려운 변수가 많이 발생해서 해결하면서 진행하다보니 시간이 많이 걸린 것 같다.

전체적인 흐름을 정리해보면

  1. GitHub에 코드를 commit & push (PR)
  2. Travis CI에서 S3로 Jar를 전달 및 CodeDeploy에 배포 요청.
  3. S3에서 전달받은 Jar를 CodeDeploy에 전달.
  4. CodeDeploy에서 배포.
  5. EC2 서버 반영.

여기서 핵심은 CodeDeploy가 저장기능이 없기 때문에 실행하기 위한 Jar를 보관해줄 역할을 S3가 담당하고 있고 Travis CI에서 실행할 Jar를 S3로 보내준다는 것이다.

이렇게 되면서 구조적으로 배포와 빌드가 분리되었고 이를 통해서 확장성을 보장받기 좋은 구조가 되었다.

S3 스토리지에 접근하기 위해서는 amazon IAM 서비스를 사용해야하고 이를 통해서 아이디와 키를 발급 받아서 인증을 통해서 접근할 수 있도록 했었다.
특히 퍼블릭 접근을 반드시 차단해야 한다는 점을 꼭 기억하도록 하자.

IAM은 EC2 서버에도 설정을 해줘야 한다는 점도 중요했다.

EC2 서버에 CodeDeploy agent를 설치했고 권한정책을 할당했었다.
그리고 이 권한 정책을 CodeDeploy의 배포 그룹을 생성하고 거기에 적용했다.

각각의 시스템별 권한과 연동정보를 설정하기 위해 traivs, codedeploy 설정을 담당할 yml 파일을 생성했다.

step1 에서는 직접 git을 pull하여 build를 진행했었고
step2 에서는 이를 자동화하도록 수정하였다.

자동화 과정에서 핵심은 별도의 배포스크립트를 작성하고 직접 git을 pull하고 build하는 과정을 제거 및 불필요한 파일들을 제외한 배포파일을 특정 디랙토리에 모아서 이를 압축하는 방식으로 변경한 부분입니다.

특히 특정 경로로 모은 이유는 Travis CI에서 선택적인 파일압축 기능을 지원하지 않기 때문이였다.

마지막으로 어플리캐이션 두개를 동시에 실행하면서 발생한 포트 충돌이 발생했지만 인스턴스 재부팅을 통해 실행중이던 어플리캐이션들을 종료하도록 진행했었다.
PID를 써서 직접 해당 포트를 사용하는 어플리캐이션만 제거하는 것이 실제 운영할때는 필요할 것이다.

오랫만에 전체적인 연동흐름을 정리하니 머리속에 조금 정리가 되는 것 같다.
인프라 환경구축은 초기에 고생은 하지만 구축하고 나서는 자주 들여다보지 않게 되서 잘 잊어먹을 수 있다.

이런식으로라도 구축 경험담을 남겨두는 것이 나한테 득이 될 것이라고 생각하며
이번 장을 마친다.

Git hub : https://github.com/kdh85/spring-aws-study.git

profile
멈추지 않는 사람이 되고 싶어요!
post-custom-banner

0개의 댓글