지속적 통합(Continuous integration, CI)과 지속적 제공(Continuous delivery, CD), 줄여서 CI/CD는 애플리케이션 개발팀이 더 자주, 안정적으로 코드 변경을 제공하기 위해 사용하는 문화와 운영 원칙, 일련의 작업 방식
CI/CD는 데브옵스을 위한 권장 사항이자 애자일 방법론의 권장 사항이기도 하다. CI/CD는 통합과 제공을 자동화함으로써 소프트웨어 개발팀이 코드 품질과 소프트웨어 보안을 보장하는 동시에 비즈니스 요구사항을 충족하는 데 집중할 수 있게 해준다.
CI : 빌드/테스트 자동화 과정
CD : 배포 자동화 과정
1. 개발자들이 개발하여 feature브랜치에 코드를 push합니다.
2. git push를 통해 Trigger되어 **CI서버**에서 알아서 Build, Test, Lint를 실행하고 결과를 전송합니다.
3. 개발자들은 결과를 전송받고 에러가 난 부분이 있다면 에러부분을 수정하고 코드를 master 브랜치에 merge합니다.
4. master 브랜치에 코드를 merge하고 Build, Test가 정상적으로 수행이 되었다면 **CI서버**에서 알아서 Deploy 과정을 수행합니다.
// action의 이름(별칭)
**name**: CI/CD
// action 트리거
**on**:
push:
branches: [ "prod" ]
// action이 가진 repo에 대한 권한
**permissions**:
contents: read
// 해야하는 작업들을 명시 (CI-CD : current-time)
**jobs**:
CI-CD:
// [runner](https://github.com/actions/runner) 의 가상머신 환경
runs-on: ubuntu-latest
// CI-CD 작업 순서
steps:
// action marketplace (오픈소스) 사용
- **uses**: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
// 옵션
**with**:
java-version: '11'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew clean bootJar
- name: Docker build & push to prod
// 수행할 스크립트 명시
**run**: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }} .
docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }}
- name: Deploy to prod
uses: appleboy/ssh-action@master
id: deploy-prod
with:
host: ${{ secrets.EC2_HOST }}
username: ec2-user
key: ${{ secrets.EC2_PRIVATE_KEY }}
envs: GITHUB_SHA
script: |
sudo docker rm -f $(docker ps -qa)
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }}
docker-compose up -d
docker image prune -f
current-time:
// 동기적으로 실행하기 위해 순서 지정
**needs**: CI-CD
runs-on: ubuntu-latest
steps:
- name: Get Current Time
uses: 1466587594/get-current-time@v2
id: current-time
with:
format: YYYY-MM-DDTHH:mm:ss
utcOffset: "+09:00" # 기준이 UTC이기 때문에 한국시간인 KST를 맞추기 위해 +9시간 추가
- name: Print Current Time
run: echo "Current Time=${{steps.current-time.outputs.formattedTime}}" # current-time 에서 지정한 포맷대로 현재 시간 출력
shell: bash
도커 이미지는 호스트와는 독립된 자체 디렉토리를 가지기 때문에 필요한 의존성을 모두 끌어와야 한다.
도커 컨테이너는 호스트와 독립된 덕분에 호스트에 설치된 python, java, node 버전과 독립적인 환경에서 개발이 가능하다.
// 도커허브에서 공개된 자바 11버전 jdk 이미지를 가져오기
// 스프링에서 gradle로 의존성 끌어오는 것
FROM [openjdk:11-jdk-slim](https://hub.docker.com/_/openjdk)
// 8080번 포트를 열어야한다는 명시
EXPOSE 8080
// images 폴더를 만든다.
RUN mkdir "images"
// 이미지 빌드 할 때 커스텀하기 위해
ARG BUILD_DIR=/build
// 컨테이너가 stop 하면 컨테이너 내의 모든 데이터가 유실되기 때문에 docker platform에 저장하기 위함
// 컨테이너가 다시 run 할때 docker platform에 있는 볼륨과 /var/log 가 싱크를 이룸
VOLUME ["/var/log"]
// 로컬의 /build 디렉토리를 도커 이미지의 /build 로 복사하겠다.
COPY ${BUILD_DIR} /build
// 컨테이너를 run 할때 실행되는 커맨드
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod","/build/libs/matdongsan-0.0.1-SNAPSHOT.jar"]
sudo docker run \
-p 8080:8080 \
—build-arg BUILD_DIR=/build \
-v /home/ec2-user/log:/var/log \
--name matdongsan \
--env TZ=Asia/Seoul
.
version: '3'
services:
woowang:
image: wangjh789/matdongsan
container_name: matdongsan
ports:
- 8080:8080
environment:
- TZ=Asia/Seoul
volumes:
- /home/ec2-user/log:/var/log