[Docker] jar 파일 생성 및 도커 파일 작성하기

Ogu·2023년 4월 30일
0

도커를 사용하는 이유

만약 똑같은 일을 하는 2대의 서버가 있다고 합시다. A서버는 1년 전에 구상했고, B서버는 이제 막 구성했다면 운영체제, 컴파일러, 패키지 등 모든 것이 완벽하게 같기는 쉽지 않습니다.
도커는 서버마다 동일한 환경을 구성하여 이러한 문제를 해결해 줍니다.
동일한 환경 구성으로 auto scaling(서버를 늘리고, 줄이고 자유 자재)에 유리합니다.
Database, Redis 등 각각 컨테이너를 도커 base 이미지로 받아서 사용합니다.

또한 도커는 하이퍼 바이저 구조를 기반으로 등장해 VM에 비해 매우 가볍고 성능이 좋습니다.

이미지란?

이미지는 코드, 런타임, 시스템 도구, 시스템 라이브러리 및 설정과 같은 응용 프로그램을 실행 하는데 필요한 모든 것을 포함하는 패키지 입니다.
이러한 이미지는 https://hub.docker.com 을 통해 Github과 유사하게 관리합니다.

컨테이너는 이러한 도커 이미지를 독립된 공간에서 실행할 수 있게 해주는 기술입니다.
Image Instance라고도 하며, 한마디로 프로그램을 실행하는 것입니다.

Dockerfile -(build)> Docker Image -(run)> Docker Container

Dockerfile이란 도커 이미지를 구성하기 위해 있어야 할 패키지, 의존성, 소스코드 등을 하나의 file로 기록한 명령 파일입니다. 이 Dockerfile을 build하여 Docker Image를 만들고, 이 Docker Image를 run하여 Docker Container를 실행시킵니다.
이미지는 컨테이너를 실행하기 위한 모든 정보를 담고 있어 더이상 새로운 서버가 추가되어도 의존성 파일을 컴파일하거나 이것저것 설치할 필요가 없습니다.

도커 파일 주요 명령어

FROM

FROM <이미지>:<태그>
FROM openjdk:11

하나의 Docker 이미지는 base 이미지부터 시작해서 기존 이미지위에 새로운 이미지를 중첩해서 여러 단계의 이미지 층(layer)을 쌓아가며 만들어집니다.
새로운 이미지를 생성할 때 기반으로 사용할 이미지를 지정합니다. 보통 Dockerfile 내에서 최상단에 위치합니다. 일반적으로 Docker Hub와 같은 Docker repository에 올려놓은 잘 알려진 공개 이미지인 경우가 많습니다.

Ubuntu 최신 버전을 base 이미지로 사용

ARG

ARG <이름>=<기본값>

이미지 빌드 시점에서 사용할 변수를 지정합니다.

COPY

COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
COPY ${JAR_FILE} ./app.jar
COPY pharmacy.csv ./

Container에 복사할 명령어로, 호스트 컴퓨터에 있는 파일이나 디렉토리를 Docker 이미지의 파일 시스템으로 복사합니다.

ADD

ADD 명령문은 좀 더 파워풀한 COPY 명령문이라고 생각할 수 있습니다. ADD 명령문은 일반 파일 뿐만 아니라 압축 파일이나 네트워크 상의 파일도 사용할 수 있습니다. 이렇게 특수한 파일을 다루는 게 아니라면 COPY 명령문을 사용하는 것이 권장됩니다.

ENV

ENV <> <>
ENV <>=<>
ENV TZ=Asia/Seoul

컨테이너에서 사용할 환경 변수를 지정합니다. ENV 명령문으로 설정된 환경 변수는 이미지 빌드 시에도 사용됨은 물론이고, 해당 컨테이너에서 돌아가는 애플리케이션도 접근할 수 있습니다.

ENTRYPOINT

ENTRYPOINT ["<커맨드>", "<파라미터1>", "<파라미터2>"]
ENTRYPOINT ["java", "-jar", "./app.jar"]

컨테이너가 실행되었을 때 항상 실행되어야 하는 커맨드를 지정합니다.

Docker Compose란?

Docker Compose는 멀티 컨테이너 도커 어플리케이션을 정의하고 실행하는 도구입니다.
보통 Docker는 싱글이 아닌 멀티 컨테이너로 배포하게 됩니다.
이러한 멀티 도커로 이루어진 서비스의 구축과 네트워크 연결, 실행 순서를 자동으로 관리해줍니다.
docker-compose.yml 파일을 작성해 1번 실행하면 설정된 모든 컨테이너를 실행시킵니다.

jar 파일 생성 및 도커 파일 작성

jar파일의 기본 경로는 build/libs/*.jar 입니다.
bootJar 테스크를 추가하기 위해 아래 코드를 buil.gradle에 추가하고 적용시킵니다.

// build.gradle
// 변경하고자 하는 이름 
bootJar {
    archiveFileName = 'app.jar'
}

gradle을 재빌드합니다.

gradlew clean
gradlew build

이름이 잘 변경된 것을 확인합니다.

프로젝트 root 폴더에 Dockerfile 파일을 생성하고 도커 파일을 작성합니다.

FROM openjdk:11
ARG JAR_FILE=build/libs/app.jar
COPY ${JAR_FILE} ./app.jar
ENV TZ=Asia/Seoul
ENTRYPOINT ["java", "-jar", "./app.jar"]

이제 도커 파일을 도커 이미지로 빌드합니다.

docker build -t 도커허브ID/도커 이미지 이름 지정 .(도커 파일 위치/현재경로)
docker build -t ogu1208/application-project-test .

docker images 명령어로 확인해봅시다.

도커를 이용해 스프링 부트 어플리케이션 싱글 컨테이너 생성(싱글 컨테이너)

이미지를 띄워봅시다.

$ docker run ogu1208/application-project-test -p 8080:8080
  • name: 컨테이너 이름 지정
  • -p : 컨테이너는 기본적으로 외부와 격리되어 있기 때문에 호스트와 컨테이너 port 포워딩 처리 (호스트:도커컨테이너)

실행이 된 것을 확인합니다.

터미널에서도 확인해봅시다. docker ps 명령어를 사용합니다.

컨테이너를 sh, bash 등의 터미널 환경으로 접근해 봅시다.

$ docker exec -it [컨테이너 이름 또는 id] /bin/bash // 컨테이너를 sh, bash 등의 터미널 환경으로 접근


docker run 명령어로 컨테이너 생성 및 시작

$ docker run application-project-test -p 8080:8080
 --name: 컨테이너 이름 지정
 -p: 컨테이너는 기본적으로 외부와 격리되어 있기 때문에 호스트와 컨테이너 port 포워딩 처리
$ docker ps 
$ docker ps -a 
$ docker exec -it [컨테이너 이름 또는 id] /bin/bash // 컨테이너를 sh, bash 등의 터미널 환경으로 접근
$ docker stop [컨테이너 이름 또는 id] 
$ docker inspect [컨테이너 이름 또는 id]
$ docker login // docker hub login 인증
$ docker build -t [docker hub id]/[이미지 이름:태그] [Dockerfile의 경로] // docker hub id를 이용하여 repository 찾기
$ docker images 
$ docker push [docker hub id]/[이미지 이름:태그]

개발환경과 운영환경 profile 분리

Spring Profile는 어플리케이션 설정을 특정 환경에서만 적용되게 하거나
환경 별(local, develop, production)로 다르게 적용할 때 사용합니다.

application-{profile}.yml
application-local.yml
application-prod.yml

application profile 환경 별 설정 분리
https://wonyong-jang.github.io/spring/2022/08/11/Spring-Profile.html

application.yml 파일을 생성하고 작성해봅시다.
local 프로파일에서도 사용하고 prod 프로파일에서도 사용하는 것은 common으로 따로 만듭니다.

# default
spring:
  profiles:
    active: local # default
    group:
      local:  # local, common profile을 그룹지어 함께 어플리케이션 구동    
        - common
      prod:   # prod, common profile을 그룹지어 함께 어플리케이션 구동  
        - common   
## 
---
spring:
  config:
    activate:
      on-profile: common   # application-common.yml 과 동일한 역할

---
spring:
  config:
    activate:
      on-profile: local

---
spring:
  config:
    activate:
      on-profile: prod

스프링부트를 작동시켜 확인해봅시다.

  • default를 local으로 했을 경우
  • default를 common으로 했을 경우

도커를 이용한 다중 컨테이너 환경 구성

local에서는 Application은 컨테이너로 띄우지 않고 테스트 하겠습니다. (컨테이너로 띄워서 디버깅 하기가 불편함)
실제 클라우드에서는 Application, DataBase, Redis, Nginx등 각각 독립적인 컨테이너로 관리합니다.

  • services : 이곳에 실행하려는 컨테이너들을 정의
  • pharmacy-recommendation-app : 서비스 명(네트워크 호스트명) / 같은 네트워크에 속한 컨테이너끼리 서비스 명으로 접근 가능
  • container_name : 컨테이너 이름
  • build : Dockerfile이 있는 위치
  • depends_on : 특정 컨테이너에 대한 의존관계
  • image : 컨테이너 생성할 때, 사용할 도커 이미지 지정
  • environment : 환경 변수
  • volumes : 호스트 디렉토리:컨테이너 디렉토리
  • ports : 접근 포트 설정(컨테이너 외부: 컨테이너 내부) / docker run -p 옵션과 같으며 개방할 포트 지정
  • restart : 컨테이너 실행 실패하는 경우 재시작 여부

Redis, Database 도커 파일 생성 및 작성

Database Dockerfile

Redis Dockerfile

mysql utf8mb4(이모티콘 설정)

[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
skip-character-set-client-handshake

[mysqldump]
default-character-set=utf8mb4

Docker Compose 파일 작성

root 폴더에 docker-compose-local.yml 파일 작성

version: "3.8"
services:
  pharmacy-recommendation-redis:
    container_name: pharmacy-recommendation-redis
    build:
      dockerfile: Dockerfile
      context: ./redis
    image: ogu1208/pharmacy-recommendation-redis
    ports:
      - "6379:6379"
  pharmacy-recommendation-database:
    container_name: pharmacy-recommendation-database
    build:
      dockerfile: Dockerfile
      context: ./database
    image: ogu1208/pharmacy-recommendation-database
    environment:
      - MYSQL_DATABASE=pharmacy-recommendation
      - MYSQL_ROOT_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
    volumes:
      - ./database/config:/etc/mysql/conf.d
    ports:
      - "3306:3306"

.env 파일 작성

깃허브에 올라가면 안될 정보들을 위한 .env파일을 루트 폴더에 생성합니다.
이 파일을 .gitignore에 추가합니다.

.gitignore에도 추가해줍니다.

도커 컴포즈를 실행해 봅시다.

-f 옵션을 이용해 어떤 컴포즈 파일을 실행시킬지 지정합니다.

 docker-compose -f .\docker-compose-local.yml up

터미널에서도 확인해봅시다.
docker-ps : 현재 실행중인 컨테이너의 리스트 확인

springboot에서 연결해봅시다.

우선 다시 yml 파일을 수정합니다.

cloud에서는 env파일이 참조되지만, local의 intellij에서는 따로 환경 변수를 설정해주어야 합니다.

운영 환경에서 사용하기

applicaion.yml

---

spring:
  config:
    activate:
      on-profile: prod
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://pharmacy-recommendation-database:3306/pharmacy-recommendation
    username: ${SPRING_DATASOURCE_USERNAME}
    password: ${SPRING_DATASOURCE_PASSWORD}
  redis:
    host: pharmacy-recommendation-redis
    port: 6379
  jpa:
    hibernate:
      ddl-auto: validate # prod 배포시 validate
    show-sql: true

pharmacy:
  recommendation:
    base:
      url: http://localhost/dir/ # aws ec2 ip 할당 받은 후 변경 예정

docker-compose.yml

version: "3.8"                                          # 파일 규격 버전
services:                                               # 이 항목 밑에 실행하려는 컨테이너들을 정의
  pharmacy-recommendation-redis:                        # 서비스명
    container_name: pharmacy-recommendation-redis       # 컨테이너 명
    build:
      dockerfile: Dockerfile
      context: ./redis
    image: zcx5674/pharmacy-recommendation-redis
    ports:
      - "6379:6379"
  pharmacy-recommendation-database:
    container_name: pharmacy-recommendation-database
    build:
      dockerfile: Dockerfile
      context: ./database
    image: zcx5674/pharmacy-recommendation-database
    environment:
      - MARIADB_DATABASE=pharmacy-recommendation
      - MARIADB_ROOT_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
    volumes:
      - ./database/config:/etc/mysql/conf.d
      - ./database/init:/docker-entrypoint-initdb.d
    ports:
      - "3306:3306"      # 접근 포트 설정 (컨테이너 외부:컨테이너 내부)
  pharmacy-recommendation-app:
    container_name: pharmacy-recommendation-app
    build: .
    depends_on:          # DB, REDIS 컨테이너가 실행된 다음 WEB을 실행시킨다.
      - pharmacy-recommendation-database
      - pharmacy-recommendation-redis
    image: zcx5674/pharmacy-recommendation-app
    environment:
      - SPRING_DATASOURCE_USERNAME=${SPRING_DATASOURCE_USERNAME}
      - SPRING_DATASOURCE_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
      - SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE}
      - KAKAO_REST_API_KEY=${KAKAO_REST_API_KEY}
    ports:
      - "80:8080"
    restart: always # depends on은 실행 순서만 컨트롤 할뿐,
    # 컨테이너 안의 서비스가 실행가능한 상태인지까지는 확인 하지 않기 때문에
    # DB 또는 Redis가 아직 실행가능한 상태가 아니여서 실패하는 경우 재시작 하도록 설정

.env 파일 수정

프로젝트를 clean build 하고 docker ps로 실행중인 컨테이너가 없는지 확인 한 후,
docker-compose up --build 명령어로 다시 스프링부트를 실행시킵니다.
(docker-compose-yml이 default 파일이기 때문에 파일 명을 명시하지 않아주어도 됩니다)

profile
Hello! I am Ogu, a developer who loves learning and sharing! 🐤🐤 <br> こんにちは!学ぶことと共有することが好きな開発者のOguです!🐤

0개의 댓글