name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push]
jobs:
Explore-GitHub-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v4
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
github repository에서 actions에 들어가보면
깃허브 액션이 자동으로 실행된다
github actions를 활용한 ci 구축하기
작성된 프로젝트에서
# Actions 이름 github 페이지에서 볼 수 있다.
name: Run Test
# Event Trigger 특정 액션 (Push, Pull_Request)등이 명시한 Branch에서 일어나면 동작을 수행한다.
on:
push:
# 배열로 여러 브랜치를 넣을 수 있다.
branches: [ develop, feature/* ]
# github pull request 생성시
pull_request:
branches:
- develop # -로 여러 브랜치를 명시하는 것도 가능
# 실제 어떤 작업을 실행할지에 대한 명시
jobs:
build:
# 스크립트 실행 환경 (OS)
# 배열로 선언시 개수 만큼 반복해서 실행한다. ( 예제 : 1번 실행)
runs-on: [ ubuntu-latest ]
# 실제 실행 스크립트
steps:
# uses는 github actions에서 제공하는 플러그인을 실행.(git checkout 실행)
- name: checkout
uses: actions/checkout@v4
# with은 plugin 파라미터 입니다. (java 17버전 셋업)
- name: java setup
uses: actions/setup-java@v2
with:
distribution: 'adopt' # See 'Supported distributions' for available options
java-version: '17'
- name: make executable gradlew
run: chmod +x ./gradlew
# run은 사용자 지정 스크립트 실행
- name: run unittest
run: |
./gradlew clean test
.github/workflows/~~.yaml파일에 위 내용을 넣는다 이름은 run test이며 develop와 feature의 모든하위브랜치에서 push가 발생하거나 develop로 pull request가 발생시 ubuntu-lastest에서 git checkout을 실행후, java17버전으로 unittest 라는 스크립트를 테스트한다.
github actions에 등록이 된것을 볼 수 있다.
사용법
pull request시 자동으로 테스트 하게된다. 만약 테스트가 실패하게 된다면 아래와같은 오류와 메일이 보내지게 된다.
github actions를 활용한 cd 구축하기
cloud type라는 무료 서비스를 사용한다.
흐름 개발자 1. 개발자는 feature/ 로 시작하는 브랜치에서 test코드를 포함한 수정 작업을 완료한뒤 pull request를 생성 자동화 2. pull request를 만들면 해당 브랜치에 대해 gradle test를 수행 개발자 3. pull request 코드의 test가 실패한 경우, pull request를 생성한 개발자는 test 코드를 수정하여 pull request를 변경 4. pull request 코드의 test가 성공한 경우, 다른 개발자들의 승인을 기다림 5. 다른 개발자들은 pull request의 코드를 승인하거나 댓글로 소통 자동화 6. main 브랜치에 merge되면 해당 브랜치를 cloudtype 서버에 배포함
cloud type 회원가입 및 카드등록
CLOUDTYPE 깃허브 저장소 배포하기
알맞는 버전, 알맞는 포트로 배포를 하면된다.
레파지토리에 시크릿 키 등록하기
repository > secrets and variables > actions에
깃허브 토큰과, cloudtype의 토큰을 저장한다
배포가 되는것을 볼 수 있다
정리 아래의 코드에 의해 pull request가 열린다면 테스트 코드를 실행시켜 통과되는것을 확인하고.
wname: test every pr
on:
workflow_dispatch:
pull_request:
permissions:
contents: read
pull-requests: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: setup jdk
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
- name: gradlew test
run: ./gradlew test
docker file 이란? docker image를 빌드하기 위한 파일이다. 어떤 파일을 실행할지, 어떤 프로그램을 설치할지, 어떤 os에서 실행할지 등등에 관한 정보가 있다. build를 하게되면, 설정파일에 있는대로 필요한 내용을 설치하게된다. 이 image를 실행하게되면 docker container가 생성된다.
# Dockerfile
FROM ubuntu:latest
MAINTAINER Your Name <your-email@example.com>
RUN apt-get update && apt-get install -y nginx
COPY index.html /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
from : 베이스 이미지를 선택, 여기서는 ubuntu 최신버전 maintainer : 이미지를 만든 사람의 정보를 입력 run : 이미지를 생성하는동안 실행할 명령어, 여기서는 패키지 목록을 업데이트하고 nginx를 설치한다. copy : 파일을 이미지에 복사, 여기서는 index.html 파일을 docker의 nginx의 디렉토리에 복사한다 expose : 컨테이너가 노출할 포트 설정, 여기서는 80포트를 노출한다 cmd : 컨테이너가 실행될 때 실행할 명령 설정, 여기서는 포그라운드에서 실행되게 설정한다.
도커 이미지 생성방법 docker build -t my-nginx:latest 처럼 실행한다.
생성된 도커 이미지 실행방법 docker run -d -p 80:80 my-nginx:latest
컨테이너 종료방법 docker stop my-nginx
그외 dockerfile 명령어 lable : 이미지에 메타데이터 추가 LABEL purpose= 'nginx test'
ENTRYPOINT : 컨테이너를 시작할때, 실행할 명령어 입력 컨테이너를 실행할때마다 실행하며, 추가적인 명령어 존재 여부와 상관없이 무조건 실행 ENTRYPOINT ["npm", "strart"]
ENV : 환경 변수를 설정 이미지 안에 각종 환경 변수를 지정 ENV STAGE staging
WORKDIR : 작업 디렉터리를 지정 WORKDIR /app
USER : 사용자를 설정 container의 기본 사용자는 root임 RUN["useradd", "user"] USER user
docker compose
docker compose를 통해 여러개의 컨테이너를 관리한다
사용해야하는 이유 간편한 설정 : 여러 컨테이너를 한 파일에 적어서 설정 가능함 자동 배포 : 설정 파일이 있으면 compose가 알아서 컨테이너들을 만들어 줌 의존성 관리 : 서로 의존하는 관계에 있으면 docker compose가 이를 관리해줌 모니터링과 로깅 : 컨테이너들의 로그를 모아줌 확장성 : 여러 컨테이너를 하나의 그룹으로 관리해줌 유연성 : 개발환경, 테스트환경, 실제 운영 환경에서도 같은 설정 파일을 써서 일관성을 유지해줌 보안 강화 : 컨테이너들의 네트워크를 분리해 외부로부터의 접근을 제한함 유지보수가 쉬움 : 설정 파일 하나로 관리가 가능
사용하는 방법 개발환경에서의 사용 : 앱을 개발할때 따로 떼어 놓고 실행할수 있음 자동화된 테스트 환경에서 : 테스트를 위한 별도의 환경을 쉽게 만들고 없앨 수 있다 단일 호스트 배포에서 : 트래픽이 적은 환경에서 실제 배포에 사용도 가능하다
장점 한번에 여러 컨테이너를 설정 가능, 빠른 서비스 실행 가능, 같은 네트워크에서 쉽게 연결 가능
yaml파일이란? 컴퓨터가 읽을수 있고, 사람이 읽기에도 쉬운 텍스트 형식이다. 일반 텍스트로 써져있으며, 목록 키-값 쌍으로 이루어져 있다 설정을 정리하고 관리하기에 좋으며, docker에서 여러 컨테이너의 설정을 한곳에 쉽게 정리 할 수 있다. 들여쓰기가 잘못된 경우 yaml파일이 의도와 다르게 해석할 수 있으니 주의해야하며 https://www.yamllint.com/ 에서 들여쓰기 검사를 해준다.
docker compose 파일 설명
#docker compose의 버전
version: '3'
# 네개의 서비스를 정의한다, web, api, redis, mysql
services:
#web 서비스는 nginx:lkatest 이미지를 사용하고, 80포트를 매핑한다.
#web 서비스는 현재 디렉토리 내 web디렉토리를 컨테이너에 연결한다, api 서비스에 의존하며, api서비스가 먼저 실행된 후에 실행된다
web:
image: nginx:latest
ports:
- 80:80
volumes:
- ./web:/usr/share/nginx/html
depends_on:
- api
links:
- api:api
#api 서비스는 java 최신버전의 이미지를 사용하고, api를 컨테이너 내부의 app 경로에 매핑한다.
#8080포트를 노출시키며, 각각의 호스트 이름을 설정하는 환경변수가 있으며 mysql과 redis에 의존하여 mysql과 redis 실행 후 실행된다.
api:
image: java:latest
volumes:
- ./api:/app
ports:
- 8080:8080
environment:
- REDIS_HOST=redis
- MYSQL_HOST=mysql
- MYSQL_USER=root
- MYSQL_PASSWORD=password
- MYSQL_DATABASE=test
depends_on:
- mysql
- redis
links:
- mysql:mysql
- redis:redis
#redis최신 이미지를 사용하며, 포트는 6379포트를 노출시킨다
redis:
image: redis:latest
ports:
- 6379:6379
#mysql 최신 이미지를 사용하며, 포트는 3306포트를 사용하고 mysql을 컨테이너 내부의 var/lib/mysql에 위치시킨다
#비밀번호와 데이터베이스명, 기본사용자와 패스워드를 설정하는 환경변수를 설정한다.
mysql:
image: mysql:latest
ports:
- 3306:3306
volumes:
- ./mysql:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=test
- MYSQL_USER=root
- MYSQL_PASSWORD=password
yaml파일
version: "3"
services:
web:
build:
context: . # Dockerfile 의 위치
dockerfile: Dockerfile # Dockerfile 파일명
container_name: testapp_web_1 # 생략하는 경우
# 자동으로 부여 docker run 의 --name 옵션과 동일
#8080포트를 8080호스트 머신과 연결한다
ports: "8080:8080" # docker run 의 -p 옵션과 동일
#호스트머신과의 연결이 아닌 링크로연결된 서비스 간 통신이 필요할때 사용한다
expose: "8080"
# networks 를 최상위에 정의한다면 해당 이름을 사용 docker run의 --net 옵션과 동일
networks: testnetwork
# 현재 디렉토리를 html 디렉토리와 연결하고 있음 docker run 의 -v 옵션과 동일
volumes: .:/var/lib/nginx/html
#환경변수
environment:
- APPENV=TEST # docker run 의 -e옵션과 동일
# 컨테이너를 실행할때 어떤 명령어를 실행할지 docker run 의 가장 마지막
command: npm start
#중지된 경우에 재시작을 하나? docker run 의 --restart 옵션과 동일
restart: always
depends_on: db # 이 옵션에 지정된 서비스가 시작된 이후에 `web`서비스가 실행
links: db # Docker가 네트워크를 통해 컨테이너를 연결하도록 정의합니다.
# 컨테이너를 연결할 때 Docker는 환경 변수를 만들고
# 컨테이너를 알려진 호스트 목록에 추가하여 서로를 검색할 수 있도록 합니다.
deploy: # 서비스의 복제본 개수 등 지정
replicas: 3
mode: replicated
service2:
# ...service2 설정
#컨테이너가 소속된 네트워크를 지정할수있으며 따로 지정하지않을경으 default_${project}와 같이 지정한다, 기본적으로 컨테이너는 같은 네트워크에 있어야 서로 통신이 가능하다
networks:
#도커 볼륨 혹은 호스트 볼륨을 마운트하여사용한다. 도커 볼륨의 경우 compose.yml 파일에 선언된 볼륨만 docker- compose.yml에서 사용할 수 있다.
volumes:
logvolume01: {} # 도커볼륨 logvolume01 선언
docker 모니터링과 로깅
모니터링이란? 컨테이너의 상태등을 확인한다
왜 중요한가? 잘 돌아가는지, 어떤 문제가있는지, 메모리는 많이 잡아먹지않는지 파악 할 수 있다 문제를 빨리 파악하고 해결 할 수 있다.
어떻게 하는가? docker stats 명령어를 사용하면 실시간으로 확인 가능하다 특정 컨테이너의 상태만 보고 싶다면 docker stats [컨테이너 이름 또는 id]
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
8b4172b8f519 spring-boot-sample-nginx-1 0.00% 18.57MiB / 15.5GiB 0.12% 1.57kB / 0B 0B / 0B 25
999c364cccaa spring-boot-sample-mysql-1 16.69% 204.3MiB / 15.5GiB 1.29% 1.57kB / 0B 0B / 0B 1
a637da33772f spring-boot-sample-redis-1 0.17% 8.883MiB / 15.5GiB 0.06% 1.57kB / 0B 0B / 0B 6
htop 시스템 모니터링의 도구 컴퓨터의 cpu 메모리 사용량 같은 정보를 실시간으로 볼 수 있음.
df 시스템 전체의 디스크 사용량을 확인 가능하다
du 디렉토리 별로 사용 공간을 나타내준다
container 로깅
docker는 모든 컨테이너의 출력 또는 에러를 캡쳐하여 json-file 로깅 드라이버를 사용하여 json형식으로 파일에 기록함. /var/lib/docker/containers/[컨테이너 id]/[컨테이너id]-json.log에 기록됨
로그 전체 출력하기 docker logs [컨테이너 이름]
지속적인 로그 출력하기 docker logs -f [컨테이너 이름]
docker volume
사용 이유 1. 데이터 영속성 : 컨테이너는 쓰고 나면 사라지는데 볼륨은 컨테이너가 사라져도 데이터는 남기때문에 2. 같은 데이터를 여러 컨테이너가 사용할 수 있게 : 볼륨으로 여러 컨테이너가 하나의 데이터를 사용할 수 있음 3. 데이터를 백업하고 옮기기 쉽게 : 백업하기 편함 4. 데이터를 안전하게 보관 : 중요한 데이터를 컨테이너밖으로 옮김으로써 안전하게 보관할 수 있음 5. 코드와 데이터의 분리 : 코드를 바꿔도 데이터는 유지 가능해서 개발할때 편함
장점 1. 백업의 간편함 2. docker 명령어로 관리한다 3. 어떤 컨테이너에도 잘돌아간다 4. 여러 컨테이너에서 사용 가능하다
volume /var/lib/docker/volumes/ 에 만들어진다
bind mount 컴퓨터의 특정 폴더나 파일을 골라서 docker 컨테이너에 붙여넣는것 절대 경로를 사용한다
ympfs mount 컴퓨터 메모리를 사용해서 일시적인 데이터를 저장한다 영구적으로 저장하는게 아닌 임시적인 저장이나, 메모리를 사용하므로 빨라진다 다만, 컨테이너끼리 공유는 되지않다
영속성 테스트
user@localhost:~$ docker container run -ti --rm -v datavol:/data alpine
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
43c4264eed91: Already exists
Digest: sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d
Status: Downloaded newer image for alpine:latest
/ # echo "볼륨 데모" > /data/memo.txt
/ # exit
user@localhost:~$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
user@localhost:~$ docker container run --rm -v datavol:/data ubuntu cat /data/demo.txt
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
dafa2b0c44d2: Pull complete
Digest: sha256:dfc10878be8d8fc9c61cbff33166cb1d1fe44391539243703c72766894fa834a
Status: Downloaded newer image for ubuntu:latest
cat: /data/demo.txt: No such file or directory
user@localhost:~$ docker container run --rm -v datavol:/data ubuntu cat /data/memo.txt
볼륨 데모
image를 한번 실행후 거기서 /data/memo.txt에 파일을 만들었다. image를 실행 종료하고, 다른 image를 생성한 후, memo.txt를 불러보았다. 그러니 볼륨 데모라는 메세지가 출력되었다. 이렇게 volume는 데이터를 남겨준다.,
docker network
도커 네트워크는 컨테이너들끼리의 통신을 쉽게하고 보안을 강화하는 역할을 한다. 실제 비즈니스 애플리케이션에는 여러 컨테이너가 협력해야하므로, 이를위해 서로간의 통신 경로인 네트워크가 필요하다. 도커는 이를위해 컨테이너 네트워크 모델 CNM을 제공한다. 출처 : 내일배움캠프 도커 5주차 2강
샌드박스 : 외부로부터 컨테이너를 격리한다. 엔드포인트 : 샌드박스와 네트워크를 연결하는 지점이다. 네트워크 : 컨테이너 간의 통신을 가능하게 하는 경로이다.
docker network 종류 브리지 네트워크 : docker의 기본 네트워크, 단일 호스트 내에서 여러 docker 컨테이너가 통신할수있게 해준다. docker가 각 컨테이너에 ip주소를 자동으로 할당한다, 외부 네트워크와는 분리되어 있지만, 포트 매핑을 통해 외부에서 접근 할 수 있다.
공용 네트워크 외부 접근이 필요한 경우 브리지 네트워크에 포트를 열거나 호스트 네트워크를 사용할수 있다. 호스트 네트워크는 컨테이너가 호스트 컴퓨터의 네트워크를 직접 사용하게 하여, 외부 네트워크와 바로 통신할수 있게 합니다.
사설 네트워크 특정 컨테이너들끼리만 통신할 수 있도록 격리된 네트워크이다. 사용자가 직접 네트워크를 정의하고, 필요한 컨테이너만 연결할 수 있어보안이 강화된다.
docker hub repositories에 image push하는법
image push registry : dockerfile을 통해 이미지를 저장하는 곳 public registry : 공개적으로 사용할수있는 곳이며 docker hub가 있다 private registry : 특정한그룹만 이미지를 접근할수있는곳.
순서
docker logout
docker login
#push할 테스트 이미지를 가져온다
docker image pull nginx:latest
docker image pull ubuntu:22.04
#push할 이미지에 태그를 달아준다 이떄 본인의 docker hub 계정 이름을 사용해야한다.
docker image tag nginx:latest 본인 계정명/nginx-test:1.0
#push한다.
docker push 본인계정명/nginx-test:1.0
#push한 도커 파일을 hub에서 pull 받아온다
docker pull 본인계정명/nginx-test:1.0
#pull한 도커파일을 실행해본다.
docker run -d -p 8001:80 --name=nginx-test 본인계정명/nginx-test:1.0
docker 파일 최적화
왜 해야하는가? 빠르게(다운로드나 업로드할때), 재사용성 높이기, 보안강화, 유지보수가 쉽다
docker container 가상화
컨테이너란? 앱을 실행하는데 필요한 코드, 언어, 라이브러리등 docker은 dockerfile을 통해 컨테이너를 만듬
장점 컴퓨터 자원을 여러앱과 나눠쓸수 있음 경량화 : 운영체제를 여러 앱과 공유를 하여, 운영체제가 필요없음, 컨테이너 파일은 작고 가벼울수 있음. 이동성 및 플랫폼 독립성 : 앱을 실행하는데 필요한걸 담기때문에 어디서든 실행가능 최신 개발 트렌드에 맞음 : 새로운 코드를 조금씩 추가하거나 업데이트할때 유용함
용도 마이크로 서비스에 좋음 : 컨테이너는 작고 가벼워서 앱을 여러 작은 부분으로 나누어 관리 할 수 있음 DevOps에 유용함 하이브리드, 멀티클라우드에 이상적임 : 컨테이너는 어디서든 잘 돌아가기때문에 여러 클라우드를 섞은 멀티 클라우드, 하이브리드등에 이상적임