목표
이전 편에서 작성한 내용에 CI/CD를 추가해보자
- 소스 위치, 버전 정보를 저장소에서 가져오자
- release 브랜치에 push가 발생하면 docker 이미지로 배포할 수 있도록 하자
- 배포 버전은 커밋ID를 넣을 수 있도록 하자
- 배포하는 이미지의 크기를 줄이자
여정
컨테이너와 프로젝트 간 의존성 제거
docker 이미지를 Registry에 등록
각 Dockerfile마다 Container Registry에 등록하여 이미지를 pull할 수 있도록 등록
# Gitlab의 Private image hub에 저장할 수 있도록 로그인 docker login registry.gitlab.com # Image naming convention에 따라 아래와 같이 Build 및 Push docker build -t <registry URL>/<namespace>/<project>/<image>:<tag> . docker push <registry URL>/<namespace>/<project>/<image>:<tag>
기존 Docker 실행관련 정보 분리
Container 정보를 가지고 있는 Docker Compose용 Repository를 새로 생성함.
→ 서비스는 서비스에만 집중하기 위함 : MSA의 특징인 인터페이스 통신을 살려보자
서비스와 DB : DB 관련 Container 정보를 몰라도 됨
DB 설정은 환경변수를 활용
# database.properties schema.name=${DB_SCHEMA_NAME} spring.datasource.username=${DB_USER} spring.datasource.password=${DB_PASSWORD} spring.datasource.url=jdbc:${DB_KIND}:${DB_DELIMITER}${DB_HOST}:${DB_PORT}/${DB_NAME}?useUnicode=true&characterEncoding=utf8¤tSchema=${DB_SCHEMA_NAME} spring.datasource.driver-class-name=${DB_DRIVER_CLASS_NAME} spring.jpa.hibernate.dialect=${DB_DIALECT} # dbType=${DB_TYPE} # JPA spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.format_sql=false spring.jpa.show-sql=false
서비스와 서비스 : 다른 서비스 Container 정보를 몰라도 됨
다음과 같은 구조를 가지게 됨
DB 설정파일
/conf/DB설정할 SQL파일(*.sql) → 각자 필요에 맞게 작성
/conf/initdb.sh
Postgres
#!/bin/bash # initdb.sh for PostgreSql # Create a database and initialize it export SQL_FILE_PATH="$CONFIG_PATH"/"$DB_TYPE".sql sudo sed -i "s/{SERVICE_B_SCHEMA_NAME}/$DB_SCHEMA_NAME/g" "$SQL_FILE_PATH" su - postgres -c "psql -U $DB_USER -c \"CREATE DATABASE $DB_NAME\"" su - postgres -c "psql -U $DB_USER -d $DB_NAME -c \"CREATE SCHEMA $DB_SCHEMA_NAME\"" su - postgres -c "psql -U $DB_USER -d $DB_NAME -a -f $SQL_FILE_PATH"
Oracle
#!/bin/bash # initdb.sh for Oracle # Create a database and initialize it export SQL_FILE_PATH="$CONFIG_PATH"/"$DB_TYPE".sql su - oracle -c "echo \"create user $DB_USER identified by $DB_PASSWORD;\" | sqlplus / as sysdba" su - oracle -c "echo \"grant dba to $DB_USER;\" | sqlplus / as sysdba" su - oracle -c "sqlplus \"$DB_USER/$DB_PASSWORD@$DB_NAME\" < \"$SQL_FILE_PATH\""
./DB Dockerfile
# Database FROM postgres:14 ENV APPNAME SERVICE_B ENV WORKDIR /usr/src/app WORKDIR $WORKDIR ENV CONFIG_PATH /usr/src/conf COPY ./conf $CONFIG_PATH # 타임존 설정 RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \ && echo $TZ > /etc/timezone # update 및 패키지 설치, init 명령어 등록 RUN apt update \ && apt install -y sudo sed \ && cat $CONFIG_PATH/initdb.sh >> /bin/initdb \ && chmod u+x /bin/initdb
환경변수 설정파일(.env)
Postgres
.env 파일(Docker Compose용)
# .env for PostgreSql WORKDIR=/usr/src/app # DB Configuration DB_HOST=db_instance # 외부 DB와 연결하고 싶을 때 DB IP 입력 DB_ENV_FILE=.env.db DB_PORT_IN=5432 DB_PORT_OUT=5432 DB_IMAGE=registry.gitlab.com/... DB_IMAGE_VERSION=postgres-7.1.0 DB_DEFAULT_PATH=/var/lib/postgresql/data # SERVICE_B Configuration SERVICE_B_IMAGE=registry.gitlab.com/... SERVICE_B_IMAGE_VERSION=latest SERVICE_B_NAME=SERVICE_B1 # SERVICE_D Configuration SERVICE_D_IMAGE=registry.gitlab.com/... SERVICE_D_IMAGE_VERSION=latest SERVICE_D_NAME=kit1 # Ports SERVICE_B_PORT_IN=8080 SERVICE_B_PORT_OUT=8080 SERVICE_D_PORT_IN=8888 SERVICE_D_PORT_OUT=8888 SERVICE_D_CACHE_PORT_IN=8900 SERVICE_D_CACHE_PORT_OUT=8900
.env.db 파일(DB용)
# DB Configuration DB_USER=... DB_PASSWORD=... # Postgresql POSTGRES_PASSWORD=${DB_PASSWORD} DB_NAME="db" DB_SCHEMA_NAME="schema" DB_KIND="postgresql" DB_DELIMITER="//" DB_DIALECT="org.hibernate.dialect.PostgreSQL10Dialect" DB_DRIVER_CLASS_NAME="org.postgresql.Driver" DB_TYPE="postgresql_table" TZ="Asia/Seoul"
Oracle
.env 파일(Docker Compose용)
# .env for Oracle WORKDIR=/usr/src/app # DB Configuration DB_HOST=db_instance # 외부 DB와 연결하고 싶을 때 DB IP 입력 DB_ENV_FILE=.env.db DB_PORT_IN=1521 DB_PORT_OUT=1521 DB_IMAGE=registry.gitlab.com/... DB_IMAGE_VERSION=oracle-7.1.0 DB_DEFAULT_PATH=/opt/oracle/oradata # SERVICE_B Configuration SERVICE_B_IMAGE=registry.gitlab.com/... SERVICE_B_IMAGE_VERSION=latest SERVICE_B_NAME=SERVICE_B1 # SERVICE_D Configuration SERVICE_D_IMAGE=registry.gitlab.com/... SERVICE_D_IMAGE_VERSION=latest SERVICE_D_NAME=kit1 # Ports SERVICE_B_PORT_IN=8080 SERVICE_B_PORT_OUT=8080 SERVICE_D_PORT_IN=8888 SERVICE_D_PORT_OUT=8888 SERVICE_D_CACHE_PORT_IN=8900 SERVICE_D_CACHE_PORT_OUT=8900
.env.db 파일(DB용)
# DB Configuration DB_USER=admin DB_PASSWORD=0000 # Oracle ORACLE_PASSWORD=${DB_PASSWORD} DB_NAME="xe" DB_SCHEMA_NAME="schema" DB_KIND="oracle:thin" DB_DELIMITER="@" DB_DIALECT="org.hibernate.dialect.Oracle10gDialect" DB_DRIVER_CLASS_NAME="oracle.jdbc.driver.OracleDriver" DB_TYPE="oracle_table" TZ="Asia/Seoul"
Docker-Compose.yml
Postgres
# Docker compose x-SERVICE_B-common: &SERVICE_B-common env_file: ${DB_ENV_FILE} image: ${SERVICE_B_IMAGE}:${SERVICE_B_IMAGE_VERSION} container_name: SERVICE_B restart: always ports: - ${SERVICE_B_PORT_IN}:${SERVICE_B_PORT_OUT} environment: NODENAME: ${SERVICE_B_NAME} DB_PORT: ${DB_PORT_OUT} DB_HOST: ${DB_HOST} networks: inner_network: ipv4_address: 172.26.0.3 x-SERVICE_D-common: &SERVICE_D-common env_file: ${DB_ENV_FILE} image: ${SERVICE_D_IMAGE}:${SERVICE_D_IMAGE_VERSION} container_name: SERVICE_D restart: always ports: - ${SERVICE_D_PORT_IN}:${SERVICE_D_PORT_OUT} - ${SERVICE_D_CACHE_PORT_IN}:${SERVICE_D_CACHE_PORT_OUT} environment: NODENAME: ${SERVICE_D_NAME} DB_PORT: ${DB_PORT_OUT} DB_HOST: ${DB_HOST} networks: inner_network: ipv4_address: 172.26.0.4 x-database-common: &database-common env_file: ${DB_ENV_FILE} image: ${DB_IMAGE}:${DB_IMAGE_VERSION} container_name: db_instance restart: unless-stopped ports: - ${DB_PORT_IN}:${DB_PORT_OUT} volumes: - db_storage:${DB_DEFAULT_PATH} - package_storage:${WORKDIR} networks: inner_network: ipv4_address: 172.26.0.2 volumes: db_storage: driver: local package_storage: driver: local networks: inner_network: ipam: driver: default config: - subnet: 172.26.0.0/16 services: database: <<: *database-common healthcheck: test: [ "CMD", "pg_isready", "-U", "postgres" ] interval: 10s timeout: 3s retries: 3 profiles: ["in_db"] SERVICE_B: <<: *SERVICE_B-common depends_on: database: condition: service_healthy profiles: ["in_db"] SERVICE_D: <<: *SERVICE_D-common depends_on: database: condition: service_healthy profiles: ["in_db"] SERVICE_B_external_db: <<: *SERVICE_B-common profiles: ["ex_db"] SERVICE_D_external_db: <<: *SERVICE_D-common profiles: ["ex_db"]
Oracle
# healthcheck 부분만 아래와 같이 바꿔주면 된다. healthcheck: test: su - oracle -c "sqlplus SELECT INSTANCE_NAME, STATUS FROM V$$INSTANCE;"
Compose 동작 확인
# 컨테이너 내부 DB로 실행하는 경우 docker compose --profile in_db up -d # DB 컨테이너에서 스크립트 실행 docker exec -it db_instance initdb # 종료 # -v : 컨테이너 볼륨도 같이 제거 docker compose --profile in_db down [-v]
# 외부 DB와 연결하여 실행하는 경우 docker compose --profile ex_db up -d # 종료 # -v : 컨테이너 볼륨도 같이 제거 docker compose --profile ex_db down [-v]
Q & A
Compose CLI 커맨드 --env-file 옵션 vs Compose파일의 env_file 옵션의 차이가 뭔가요?
--env-file : Docker compose 파일 안에서 env파일을 환경변수로 참조할 수 있게 해준다.
env_file : 해당 env파일의 환경변수는 compose 파일에서 참조할 수 없으며, Dockerfile 내에서만 유효하다.
# env_file 옵션은 아래와 같은 효력을 지닌다. docker run --env-file=FILE …
오라클 DB에러가 발생했어요, ORA-01031 : insufficient privileges
DBA 권한이 없는 유저로 접속시도한 경우에 발생합니다.
sqlplus / as sysdba
와 같이 관리자 모드로 실행하면 됩니다.su - oracle -c "echo \"create user $DB_USER identified by $DB_PASSWORD;\" | sqlplus / as sysdba"
오라클 DB에러가 발생했어요, ORA-01109: database not open
데이터베이스 읽기, 쓰기 권한이 열려있지 않은 경우에 발생하는 에러입니다
아래 명령어를 통해 Open 상태로 변경할 수 있습니다.
sqlplus / as sysdba ALTER DATABASE OPEN;
하지만, 제 경우에는 Oracle DB가 완전히 기동되기 전에 실행하려해서 발생했습니다.
아래와 같은 명령어로 기동 상태를 확인할 수 있습니다.
sqlplus SELECT INSTANCE_NAME, STATUS FROM V$$INSTANCE;
su - oracle -c "echo \"create user $DB_USER identified by $DB_PASSWORD;\" | sqlplus / as sysdba"
컨테이너를 계속 켜놓고 싶어요
# keep running ENTRYPOINT ["tail", "-f", "/dev/null"]
리눅스에서 특정 파일을 찾고 싶어요
# find ${경로} -name ${이름} -type [d : 디렉토리][f : 파일] find / -name test -type d
쉘 스크립트에서 Bad interpreter 오류가 발생합니다
윈도우와 리눅스 개행문자 차이로 인해 발생하는 문제입니다.
개선할 점
health check 스크립트 통일
#! /bin/sh # Wait for PostgreSQL until nc -z -v -w30 "$DB_HOST" 5432 do echo 'Waiting for PostgreSQL...' sleep 1 done echo "PostgreSQL is up and running"
참고자료
DinD(docker in docker)와 DooD(docker out of docker) | 아이단은 어디갔을까 (aidanbae.github.io)
.gitlab-ci.yml
파일에 Docker 이미지 빌드 단계 추가 - GitLab CI Workshop (infograb.io)
CI/CD 프로세스 구축기 2. 파이프라인 구성 | by kyeong su kim | 월요일 오후 9시 | Medium
GitLab Runner 를 사용하여 GitLab CI 구성하기 (tistory.com)
[Gitlab-CI/CD] window에서 Gitlab CI/CD를 docker로 배포하는 방법 (tistory.com)
[GitLab] docker-compose를 이용하여 GitLab Runner추가하기 (tistory.com)
'DevOps' 카테고리의 다른 글
쿠버네티스 비긴즈 - 간단한 서비스 배포하기 (0) | 2023.02.04 |
---|---|
쿠버네티스 비긴즈 - On-Premise 환경 구성 (0) | 2023.01.25 |
MSA Dockerizing (2) - 다듬기 (0) | 2023.01.19 |
MSA Dockerizing (1) - 시작하기 (0) | 2023.01.19 |
Let's Go Docker (3) - 심화편 (0) | 2023.01.18 |