-
AWS CodeDeploy를 활용한 배포개발 2020. 3. 17. 03:52
*이 포스트는 AWS의 CodeDeploy를 통한 EC2 서버 관련하여 업무 기록을 남기기 위해 작성 하였다.
먼저 해당 작업을 위해서 사전에 준비되어야 하는건 "Jenkins, AWS 계정" 두가지다.
전체적인 AWS CodeDeploy를 통해 배포를 처리하는 플로우는 아래와 같다.
1. Jenkins를 통한 Build Trigger
2. Jenkins-CodeDeploy Plugin 을 통한 S3로의 결과 파일 업로드
3. Jenkins-CodeDeploy Plugin 을 통한 배포 실행
4. EC2 CodeDeploy Agent를 통해 S3에서의 데이터 Polling
5. 최종 배포 파일(zip) 상의 yml을 참고하여 Shell Script 실행과 같은 추가 작업 실행
아래 내용은 위에서 나열한 플로우에 필요한 부분들을 각각 설명하고 그에 따른 셋팅 방법을 설명하고자 한다.
1. EC2 생성
> AWS 레퍼런스 문서에는 아래와 같이 EC2에 대해 설명하고 있다.
"Amazon Elastic Compute Cloud(Amazon EC2)는 Amazon Web Services(AWS) 클라우드에서 확장식 컴퓨팅을 제공합니다. Amazon EC2를 사용하면 하. 드웨어에 선투자할 필요가 없어 더 빠르게 애플리케이션을 개발하고 배포할 수 있습니다. Amazon EC2를 통해 원하는 만큼 가상 서버를 구축하고 보안 및 네트워크 구성과 스토리지 관리가 가능합니다. 또한 Amazon EC2는 요구 사항이나 갑작스러운 인기 증대 등 변동 사항에 따라 신속하게 규모를 확장하거나 축소할 수 있어 서버 트래픽 예측 필요성이 줄어듭니다."
위 내용을 간결하게 말하면 Amazon 클라우드 상에서 제공되는 가상의 컴퓨터 (Vmware나 VirtualBox 와 같음) 이다.
배포의 경우 최종적으로 EC2 서버로 진행할 것이기에 EC2 서버를 생성하여야 한다.
해당 EC2 는 아래와 같은 역할(Role)을 가지고 있어야 서버 내에서 실행되는 Application 도 같은 권한을 가지고 동작할 수 있으므로 먼저 EC2 서버를 만들기 전 Role 을 생성할 필요가 있다.
EC2에 설정할 역할에서 필요한 정책은 아래 4가지이다. 콘솔 서비스에 접속하여 해당 정책을 가진 Role을 생성한다.
위와 같이 Role을 생성하고 다음으로 생성한 Role을 사용하여 EC2 서버를 셋팅한다.
이 포스트는 EC2 인스턴스 셋팅에 관한 포스트는 아니므로 간략하게 생성한 Role을 셋팅하는 것을 설정하는 부분만 설명하겠다.
아래와 같이 인스턴스 생성 중 IAM을 설정하는 부분이 있고 해당 설정에 위에서 생성한 Role을 설정하면 된다.
(현재 사내 AWS 계정으로 테스트 중이므로 Role을 생성할 권한이 없어 기존 생성되어있는 Role을 기준으로 설명한다.)
아래 설정을 제대로 하지 않을 경우 EC2 인스턴스의 CodeDeploy Agent 가 권한을 갖지 못하여 다양한 Error를 뱉어내므로 꼭 확인하고 설정하여야 한다.
Error가 발생하고 원인을 분석하기 위해서는 설정 한 부분들을 하나하나 다시 봐야하므로 꽤나 번거로운 작업이 될 수 있다.
이렇게 생성한 EC2 서버는 CodeDeploy Agent가 설치되어 있어야 하며 CodeDeploy가 AWS의 CLI를 사용할 수 있도록 사용자도 생성되어야 한다.
생성된 EC2 인스턴스에 접근하여 아래 명령어를 통해 CodeDeploy Agent를 설치하자
sudo yum update sudo yum install ruby sudo yum install wget cd /home/ec2-user wget https://bucket-name.s3.region-identifier.amazonaws.com/latest/install chmod +x ./install sudo ./install auto
설치된 Agent의 경우 아래 명령어를 통해 실행, 정지, 상태 체크를 할 수 있다
sudo service codedeploy-agent status sudo service codedeploy-agent start sudo service codedeploy-agent stop sudo service codedeploy-agent restart
참고로 이후 CodeDeploy Agent의 로그를 보기 위해서는 아래 경로의 파일을 확인하면 된다.
codedeploy-agent.log 가 기본적으로 생성되는 로그라면 codedeploy-agent.aws_wire.log은 추가 설정을 해야 나오는 로그다.
(Agent가 비정상 동작하여 확인을 위해 옵션을 활성화하여 상세 로그를 보기위해 설정하였다.)
또한 현재 인스턴스에서 AWS CLI를 통해 CodeDeploy를 실행할 수 있게 사용자를 생성하였을테니 해당 사용자를 셋팅하여야 한다.
CodeDeploy Agent의 경우 설치 후 실행하였지만 EC2를 재기동 하였을 때는 자동으로 기동되지 않으니 아래와 같이 등록하여 인스턴스가 재기동 되어도 동작할 수 있도록 한다.
sudo vim /etc/init.d/codedeploy-startup.sh #!/bin/bash echo 'Starting codedeploy-agent' sudo service codedeploy-agent restart sudo chmod +x /etc/init.d/codedeploy-startup.sh
여기까지 완료 했다면 일단 EC2의 설정은 끝이다.
2. CodeDeploy 생성
> AWS 레퍼런스 문서에는 아래와 같이 CodeDeploy에 대해 설명하고 있다.
"CodeDeploy는 Amazon EC2 인스턴스, 온프레미스 인스턴스, 서버리스 Lambda 함수 또는 Amazon ECS 서비스로 애플리케이션 배포를 자동화하는 배포 서비스입니다."
CodeDeploy의 경우 EC2 서버에 접근하여야 하므로 그에 따른 Role을 사전에 생성하고 CodeDeploy 생성 시 설정하여야 한다.
위와 같이 CodeDeploy를 위한 정책을 설정한 Role을 만들고 해당 Role을 설정하여 CodeDeploy를 생성한다.
먼저 CodeDeploy 어플리케이션을 생성하고 해당 어플리케이션에 배포 그룹을 생성하면서 위에서 생성한 Role을 셋팅한다.
과정 중 CodeDeploy가 EC2 인스턴스를 구분하기 위한 Tag를 설정한다. (Tag의 경우 EC2 인스턴스 생성 시 설정할 수 있다)
위 과정이 끝나면 CodeDeploy 생성도 끝이다.
추가로 S3 버킷도 생성하여야 하지만 이 부분은 특별한 과정은 없으므로 "생략"한다.
3. Jenkins 셋팅
Jenkins에서 지금까지 해온 셋팅을 토대로 동작하게 하기 위해서는 Jenkins 플러그인이 설치되어 있어야 한다.
아래 CodeDeploy Plugin 설정 전 아래와 같이 Gradle 빌드 후 Shell 을 실행하도록 하였다. 해당 Sehll을 실행하는 이유는 아래 CodeDeploy Subdirectory를 보면 알겠지만 단일 값만 입력 가능하여
필요한 파일을 한곳에 몰아넣기 위함이다.
프로젝트 셋팅에서 추가로 설명하겠지만 이미 프로젝트에서 deploy 디렉토리 안에는 appspec.yml 와 배포 시 추가로 실행될 Shell 들이 위치해있다.
설치 할 플러그인의 정보는 링크를 통해 확인 가능하다.
https://plugins.jenkins.io/codedeploy/
플러그인까지 설치되었다면 Job을 생성하고 해당 Job의 Post-build Actions를 추가하여 CodeDeploy 플러그인이 실행되도록 설정 할 수 있다.
각 프로퍼티를 대략적으로 설명하자면
AWS CodeDeploy Application Name
생성한 CodeDeploy 어플리케이션명
AWS CodeDeploy Deployment Group
CodeDeploy 에서 생성한 배포 그룹명
AWS CodeDeploy Deployment Config
CodeDeploy 배포 방식 설정
S3 Bucket
생성한 S3 Bucket명
Subdirectory
프로젝트 기준 배포에 포함될 파일이 저장된 Directory
Include Files
Subdirectory 상에 배포에 포함될 파일 (패턴에 따라 파일을 수집하여 zip을 생성하여 S3 에 업로드)
위와 같이 설정하여 Use Access/Secret keys 를 선택하여 이전에 CodeDeploy CLI를 위해 생성한 유저의 Access/Secret key를 설정한다.
설정이 완료되면 다음으로 해야 할 작업은 Project 설정이다.
예제로 사용될 프로젝트는 Java SpringBoot 기반의 프로젝트로 접속 시 "index" 문자열만 화면에 출력하는 프로젝트다.
프로젝트 Bitbucket 경로
→ http://code.skplanet.com/projects/HRWP/repos/iot_platform_aws_deploy/browse
위 경로의 프로젝트를 내려받으면 위와 같은 구조로 되어있는데 CodeDeploy를 통해 배포를 했을 때 꼭 설정해야 하는 파일은 appsec.yml 파일이다.
해당 yml 의 설정을 통해 내려받은 배포 파일로 어떤 작업을 할지 정하게 된다.
version: 0.0 os: linux files: - source: / destination: /home/ec2-user/deploy # 전송 받은 zip 파일의 압축을 푼 deployment-archive 기준임. / 일 경우 그 바로 하위 # 압축이 풀리는 경로는 /opt/codedeploy-agent/deployment-root/68fbdf27-8afe-4251-a4fe-1b44ab8becfc/d-3JZ4VD3A2/deployment-archive/ # 와 같이 매번 새로 생성된다. 생성된 파일에 권한이 생기고 files에 셋팅된대로 파일이 옮겨지는 듯 하다. permissions: - object: / pattern: "**" owner: ec2-user group: ec2-user mode: 755 hooks: ApplicationStart: - location: run.sh timeout: 60 #runas: ec2-user
동작 과정을 보면 S3로부터 내려받은 배포 zip파일은 /opt/codedeploy-agent/{GUID}/{배포ID}/deployment-archive 로 압축이 풀리게 되고, 파일들은 permissions 의 설정 값에 의해 권한 값이 변경된다.
압축을 풀 당시에는 root:root 에 600 권한으로 생성되고 files 의 설정 값에 의해 이동되어진다.
마지막으로 hooks 에 설정한 Shell 이 각 단계(아래 표 참고)에서 실행된다.
ApplicationStop DownloadBundle BeforeInstall Install AfterInstall ApplicationStart ValidateService 기본적으로 모든 실행은 root 에서 실행되는데 runas 로 ec2-user로 변경하였을 때 정상적으로 기동하지 않아서 원인은 찾는 중이다. 따라서 실행된 프로세스 또한 root로 실행 중이다.
동작 테스트를 위해 inbound TCP포트 8080을 열어두고 배포된 SpringBoot 어플리케이션을 8080포트로 접속 할 수 있게 설정 하였다.
그에 따른 결과는 아래와 같이 정상적으로 접속 가능하다.
참고로 소스는 아래와 같이 작성하였다.
package com.skp.iot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @SpringBootApplication public class IotPlatformDeployApplication { public static void main(String[] args) { SpringApplication.run(IotPlatformDeployApplication.class, args); } @RestController public static class Controller{ @GetMapping({"/", "/index"}) public Mono<String> index(){ return Mono.just("index"); } } }
'개발' 카테고리의 다른 글
AWS IOT Rule Engine 을 통한 Elasticsearch 연동 (0) 2020.03.20 AWS Elasticsearch (0) 2020.03.20 SSL이란? (0) 2020.03.17 AWS IOT Solution (0) 2020.03.17 OAuth2 동작 원리 (0) 2020.03.17