Spring & Docker

박영준·2023년 3월 3일
0

Spring

목록 보기
13/58

1. Docker

1) 정의

  • Docker 는 Go언어로 작성된 리눅스 컨테이너 기반으로 하는 오픈 소스 컨테이너화 플랫폼
    → 이를 통해, 개발자는 어플리케이션을 컨테이너로 패키징할 수 있다.
    → Docker 0.9버전부터는 직접 개발한 libcontainer 컨테이너를 사용

  • 기본적으로 개발자가 단일 API를 통한 업무 절감 자동화 & 간단한 명령을 통해,
    컨테이너를 빌드/배치/실행/업데이트/중지할 수 있도록 해주는 툴킷

  • Docker 를 사용하지 않고도 컨테이너를 구축할 수 있으나
    Docker 플랫폼을 이용하면, 컨테이너를 보다 쉽고/간편하고/안전하게 빌드/배치/관리할 수 있다.

2) Legacy (레거시)

(1) 정의

"legacy" 는 사전적으로 "유산" 이라는 뜻이다.

이와 같은 맥락으로
IT 에서 "legacy" 는 "프로그래밍 언어, 플랫폼, 기술 등...에서 과거로 부터 물려 내려온 것들" 을 의미한다.
→ 대부분의 기업들은 중요한 업무를 처리하는 레거시 응용프로그램들과 데이터베이스를 가지고 있다.

예를 들면
회사에서 'visual studio 2015' 를 쓰고 있는데, 'visual studio 2019' 가 새로 나왔다.
이 때, 'visual studio 2019' 에 맞게 코드를 버전업 시켜야 할 경우, 'visual studio 2015'를 legacy라고 부른다.

(2) 흐름

(3) 문제점

어플리케이션은 모든 환경에서 동일하나, 각 환경의 서버의 OS 나 그 위에 올라가 있는 미들웨어 프로그램들은 동일하지 않다.
(의존성 문제, 제품 자체가 달라 생기는 문제 등...)

때문에,
개발자 개인 PC 에서는 어플리케이션이 정상 작동하는데, 테스트환경에서는 오류가 발생하는 문제가 발생할 수 있다.
→ 프로덕션 환경을 기준으로 다른 환경을 맞춘다고 해도, 여전히 문제가 발생한다.
(어떤 문제? 무겁다. 이식과 확장에 불리하다. 관리가 복잡하다 등...)

3) Docker 의 필요성

  1. 개선되고 완벽한 이식성
    LXC 컨테이너
    종종 시스템 특정 구성을 참조

    Docker 컨테이너
    데스크탑, 데이터 센터 및 클라우드 환경에서 수정 없이 실행된다

  2. 보다 경량의 중량과 보다 미세한 업데이트
    LXC 컨테이너
    다수의 프로세스를 단일 컨테이너 내에서 결합

    Docker 컨테이너
    각 컨테이너에서 오직 하나의 프로세스만 실행
    → 업데이트나 수리를 위해, 해당 파트 中 하나를 중지하는 동안에도 계속 실행될 수 있는 애플리케이션을 빌드 가능

  3. 자동화된 컨테이너 작성
    Docker 컨테이너
    애플리케이션 소스 코드를 기반으로 컨테이너를 자동으로 빌드

  4. 컨테이너 버전화
    Docker 컨테이너
    컨테이너 이미지의 버전을 추적,
    이전 버전으로 롤백,
    버전을 빌드한 사용자와 빌드 방법을 추적

    단, 심지어 이는 기존 버전과 새 버전 사이의 델타만 업로드 가능

  5. 컨테이너 재사용
    특히 새 컨테이너를 빌드하기 위한 템플릿처럼, 기존 컨테이너는 기본 이미지로 사용 가능

  6. 공유 컨테이너 라이브러리
    개발자는 수천 개의 사용자가 기여한 컨테이너를 포함하는 오픈 소스 레지스트리에 액세스 가능

4) '가상화'를 사용하는 이유

향상된 컴퓨터의 성능을 더욱 효율적으로 사용하기 위해 가상화 기술이 많이 등장했다.

그러나
서버 관리자 입장에서는 이런 가상화 기술의 CPU사용률은 10%대 밖에 되지 않아 서버의 리소스 낭비가 돼버린다.
그렇다고 모든 서비스를 한 서버 안에 올린다면, 안정성에 문제가 생길 수 있다.

→ 그래서, 안정성을 높이며 + 리소스도 최대한 활용 = 서버 가상화

예시 : 가상화 플랫폼 VM (OS가상화)

참고: 가상화 (Virtualization)

5) 컨테이너

(1) 정의

  • 가상화 기술 中 하나

  • 어플리케이션 소스 코드를 임의의 환경에서
    해당 코드의 실행에 필요한 OS 라이브러리 및 종속 항목과 결합하는
    실행 가능한 표준 컴포넌트

  • 대표적으로 LXC (Linux Container) 가 있다.

  • (기존 OS 를 가상화시키던 것과 달리) 컨테이너는 OS 레벨의 가상화로 프로세스를 격리시켜 동작하는 방식

(2) 필요성

  1. 경량의 무게
  • VM 과는 달리, 전체 OS 인스턴스와 하이퍼바이저의 페이로드(payload)를 전달하지 않는다.
    → 오직 코드 실행에 필요한 OS 프로세스와 종속 항목만 포함

  • 컨테이너 크기는 메가바이트(MB) 단위로 측정된다.(일부 VM 의 경우는 GB 단위)
    → 하드웨어 용량을 보다 잘 활용. 구동 시간이 보다 빠름

  1. 리소스 효율성 향상
  • 컨테이너를 사용하는 경우, VM 을 사용할 수 있는 동일 하드웨어에서 어플리케이션의 다수의 사본을 여러 번 실행 가능
    → 클라우드 비용 절감
  1. 개발자 생산성 향상
  • (VM 에 비해) 빠르고 + 간편한 배치 + 프로비저닝 및 재시작이 가능
    → 지속적 통합 및 지속적 딜리버리(CI/CD) 파이프라인에서 사용하기에 이상적
    → 애자일 및 DevOps 사례를 채택하는 개발 팀에게 매우 적합
  1. 분산형 어플리케이션의 딜리버리를 간소화한다.
    → 기업들이 클라우드 네이티브 개발 및 하이브리드 멀티 클라우드 환경으로 이전하면서 점점 인기

(3) 컨테이너 기술과 VM(가상머신)

즉, Docker 와 VM 의 비교를 말한다.

공통점

리소스 격리성을 제공하여,
어플리케이션마다 다른 컴퓨터에서 실행되는 것처럼 IP 나 PORT 등...을 다르게 설정할 수 있다.

차이점

컨테이너 기술

  • Docker의 기반 기술은 리눅스 컨테이너 기술이다. (LXC)

  • Docker는 애플리케이션 단위 가상화를 한다.

  • Docker는 각각의 애플리케이션의 격리성을 제공한다.

  • Docker는 필요한 부분만 격리가 되어있고 나머지는 공유하기 때문에 가상 머신 보다 훨씬 가볍다. (호스트 OS 공유, 이미지 레이어 공유)

  • Docker는 호스트 OS의 자원을 공유한다.

  • Docker는 가상 머신만큼 견고한 격리성을 제공하지는 않는다.

  • Docker는 리눅스의 컨테이너를 이용한 기술로, OS 위에 다른 OS를 실행하는것이 아니므로 가상 머신보다 좋은 성능을 낼 수 있다.

  • Docker는 컨테이너의 관점에서 개발자와 사용자 커뮤니티를 중심으로 혜택을 제공하는 데 있다.

  • EC2에서도 OS 단위 가상화를 하고 있다. => EC2에 도커를 올려서 사용도 가능하다. => 게스트 OS 위에 Docker 위에 컨테이너 올라가는 모양이다.

가상머신

  • VM에는 VirtualBox, VMware 등이 있다.

  • VM은 OS 단위 가상화를 한다.

  • VM은 애플리케이션에 대한 환경 격리성을 중심으로 제공한다.

  • VM은 개발 환경이나 사용 환경을 이미지로 저장하고, 호스트 OS 위에 게스트 OS를 올리는 방식이다.

  • VM은 컴퓨터의 하드웨어 자체를 가상화 시키기 때문에 컨테이너보다 가상 머신이 훨씬 무겁다.

    참고: 가상화 (Virtualization)

6) VM 가상화 플랫폼 vs Docker 가상화 플랫폼

VM 가상화 플랫폼

  • 한 서버의 여러 OS 를 가상화하여 사용 (OS 가상화)

  • Host OS 위에 + 가상화를 시키기 위한 Hypervisor 엔진 위에 + Guest OS 를 올려 사용
    → 가상화된 하드웨어 위에 OS가 올라가는 형태
    → 거의 완벽하게 Host와 분리된다.

  • 장점

    • Host OS와 완전히 분리
    • (컨테이너 기반 가상화보다) 높은 격리 레벨을 지원
      → 보안 측면에서 유리
    • 커널을 공유 X
      → 즉, 멀티 OS 가 가능하다.
      → Linux 위에 Window 를 올릴 수 없다.
  • 단점 : OS 위에 + OS를 올리기 때문에, 무겁고 느리다.

Docker 가상화 플랫폼

  • 컨테이너 방식으로 프로세스를 격리시켜 동작 (컨테이너 기반 가상화)

  • Docker 엔진 위에 + Application 실행에 필요한 Bin(= Binary, 바이너리, 이진코드, 텍스트형식이 아닌 실행 파일 or 이미지 파일)만 올라가게 된다.
    (Bin = Binary 바이너리 = 이진코드 = 텍스트형식이 아닌 실행 파일 or 이미지 파일)

  • Host OS + Docker 엔진 위에서 바로 동작하며, Host의 커널을 공유
    → 커널을 공유하게 되면, I/O 처리가 쉽게 되어 성능의 효율 ↑
    (I/O 처리 : 입출력 처리. (컴퓨터는 크게 연산, 입출력 처리 2가지를 한다))

  • 컨테이너를 사용하는 것 : 가상 머신을 생성하는 것이 아니라, Host OS 가 사용하는 자원을 분리하여 여러 환경을 만들 수 있도록 하는 것

  • 장점

    • 성능 향상
    • 뛰어난 이식성
    • 유연성 : 쉽게 Scale Out 을 할 수 있다.

7) Docker Image

(1) 정의

  • 컨테이너를 실행할 수 있는 실행파일, 설정 값들을 가지고 있는 것

  • Image 를 컨테이너에 담고 실행을 시킨다면, 해당 프로세스가 동작

  • Docker Image 를 Pull받기 위한 url 을 적지 않으면, default 로 Docker Hub에서 Image를 pull 받게되고
    url 을 적어준다면, 사설 저장소에서 이미지를 받을 수 있다.

(2) 이미지가 만들어지는 방법

ubuntu 이미지를 만들기 위해서 → Layer A,B,C 가 들어간다.

nginx 이미지를 만들기 위해서 → 이미 Layer A,B,C 로 만들어진 ubuntu 이미지를 베이스 이미지로 사용하여, 여기에 nginx 만 더한다.

web app 이미지를 만들기 위해서 → 이미 만들어진 nginx 베이스 이미지에 web app을 올려 이미지를 만든다.(ubuntu 이미지에 nginx를 올리고 web app을 올리는 것이 X)

(3) Docker File

① Docker Hub

  • Docker Image들을 저장하고 배포

  • 많은 회사들은 Docker Hub를 통해 소프트웨어를 배포 (GitHub와 동일하게 생각해도 무관)

  • 우린 Docker hub에서 image를 pull하여 간단하게 컨테이너에 넣어 사용 가능
    → 만약 배포판이 없다면? 배포판 보다 더욱 보완하고 싶다면? 그럴때 사용 할 수 있는 것이 Docker Fille 다.

② Docker File

$ vim Dockerfile

FROM ubuntu:14.04
  
# app 디렉토리 생성
RUN mkdir -p /app

#Docker 이미지 내부에서 RUN, CMD, ENTRYPOINT의 명령이 실행될 디렉터리를 설정합니다.
WORKDIR /app

# 현재 디렉터리에 있는 파일들을 이미지 내부 /app 디렉터리에 추가함
ADD     . /app

RUN apt-get update
RUN apt-get install apache2
RUN service apache2 start

VOLUME ["/data", "/var/log/httpd"]

# 하기 포트를 외부로 노출합니다.
EXPOSE 80
      
# 쉘을 사용하지 않고 컨테이너가 시작되었을 때 logbackup 스크립트를 실행
CMD ["/app/log.backup.sh"]

:wq!
  • 이미지 생성 출발점

  • 이미지를 구성하기 위한 명령어들을 작성하여, 이미지를 구성 가능
    → 즉, "Docker File을 읽을 수만 있다면, 해당 이미지가 어떻게 구성되어 있는지도 알 수 있다."

  • Docker Image 를 만들기 위한 설정 파일
    → 명령어를 토대로 Docker File을 작성하면 설정된 내용대로 Docker Image를 만들 수 있다.

  • 주의!

    • 컨테이너에 담을 파일들은 Dockerfile 하위 디렉토리에 있어야 한다.
    • Dockerfile 안에서 ADD 시, 절대 경로는 사용 불가능

FROM

  • 기반이 되는 이미지 레이어
  • <이미지 이름>:<태그> 형식으로 작성
    ex) ubuntu:14.04

MAINTAINER

  • 메인테이너 정보

RUN

  • 도커이미지가 생성되기 전에 수행할 쉘 명령어

VOLUME

  • 디렉터리의 내용을 컨테이너에 저장하지 않고, 호스트에 저장하도록 설정
  • 데이터 볼륨을 호스트의 특정 디렉터리와 연결하려면, docker run 명령에서 -v 옵션을 사용해야 합니다.
    ex) -v /root/data:/data

CMD

  • 컨테이너가 시작되었을 때 실행할 실행 파일 또는 셸 스크립트
  • 해당 명령어는 DockerFile 내 1회만 쓸 수 있다.

WORKDIR

  • CMD 에서 설정한 실행 파일이 실행될 디렉터리

EXPOSE

  • 호스트와 연결할 포트 번호

③ dockerignore

$ vim dockerignore

node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
.vscode

:wq!
  • dockerignore 파일 생성시, Docker 이미지 생성 시 이미지안에 들어가지 않을 파일을 지정 할 수 있다.

④ 작성 된 Docker File로 Image 만들기

$ docker build -t [만들고싶은 이미지 이름] 

해당 명령어는 반드시 DockerFile 경로에서 입력해야 힌다.

(4) Docker Registry

① 정의

  • (Docker Hub 처럼 공개된 방식이 아닌) 비공개적으로 격리된 저장소를 구축

② 사용법

  1. Docker 설치
    1) Docker 설치

    $ curl -fsSL https://get.docker.com/ | sudo sh
    $ service docker start
    $ docker version

    2) Docker Image Pull 받기

    $ docker pull [Image Name]

    Docker 이미지 내역은 Docker Hub 에서 확인 할 수 있다.

    ※ DockerHub 에서 Official 이 공식 배포 버전
    ※ Version 명시가 없을시 latest(최신버전)으로 Pull
    ※ Image 앞에 Url이 없을경우 default 로 DockerHub에서 pull 사설 레지스트리에서 받을시 앞에 Url 작성

    3) Docker Image list 확인

    $ docker images
    
    ## 다음과 같이 이미지가 만들어진다. 
    REPOSITORY       TAG            IMAGE ID       CREATED       SIZE
    docker-example   0.0.1          378107e4a39d   3 hours ago   454MB

    4) Docker Image 삭제하기

    $ docker rmi [이미지 이름]

    ※ 이미지 삭제 시, 뒤에 버전까지 명시 해야한다.
    ※ 버전 생략 시, latest 최신 버전으로 삭제

    5) Docker Image Push 하기

    $ docker push [레지스트리url/이미지:버전]

    6) Docker Image로 컨테이너 실행시키기

    $ docker run <옵션> <이미지 이름, ID> <명령> <매개 변수>

    7) Docker List 확인 [컨테이너]

    $ docker ps (실행중인 컨테이너만 확인)
    
    $ docker ps - a (종료된 컨테이너까지 확인)
    CONTAINER ID  IMAGE                            COMMAND                          .....     PORTS                                     NAMES
    
    08d9361ea25f   eclipse-mosquitto  "/docker-entrypoint.…"  .....   0.0.0.0:1883->1883/tcp    jovial_wright

    8) Docker 컨테이너 log 확인

    $ docker logs –f [컨테이너 이름]

    9) Docker 컨테이너 내부 디렉토리 들어가기

    $ docker exec -i -t [컨테이너 이름] bash

    10) Docker 컨테이너 종료

    $ docker kill [컨테이너이름]

    11) Docker 종료된 컨테이너 실행시키기

    $ docker start [컨테이너이름]

    12) Docker 컨테이너 삭제

    $ docker rm [컨테이너이름]
  2. Make Open SSL

    $ mkdir -p /data/certs
    $ openssl req \
      -newkey rsa:4096 -nodes -sha256 -keyout ~/data/certs/server.key \
      -x509 -days 36500 -out ~/data/certs/server.crt
  3. Docker Registry에 접속 할 장비들 설정
    1) 접속할 장비들에 server.crt 파일 복사

    $ mkdir -p /etc/docker/certs.d/docker-registry.khj93tistory.com
    $ cp /data/certs/server.crt /etc/docker/certs.d/docker-registry.khj93tistory.com:5000/server.crt

    2) 접속할 장비들에 hosts 등록 (localhost일 경우 127.0.0.1)

    $ vim /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4 docker-registry.kh93tistory.com
    :wq!
  4. Docker Registry Image Pull / Start

    $ docker pull registry
    $ docker run -d -p 5000:5000 --restart=always --name docker-registry   -v /data/certs:/certs   -e 
    REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server.crt   -e REGISTRY_HTTP_TLS_KEY=/certs/server.key   -v /data/certs/auth:/auth   -e "REGISTRY_AUTH=htpasswd"   -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"   -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd   registry

    Docker 실행 및 종료 명령어들은 script 로 만들어 한 곳에 모아두면 손쉽게 start/stop 가능

  5. Docker Registry Image Push

    $ docker push docker-registry.kh93tistory.com:5000/[Image Name]:[tag]

8) Docker Container

  • Docker Image 의 실행 중인 라이브 인스턴스

  • 사용자는 이들과 상호 작용 가능

  • 관리자는 docker 명령을 사용하여, 자체 설정과 조건을 알맞게 조정 가능

9) Docker Daemon

  • Microsoft Windows 또는 Apple MacOS 또는 iOS 등의 운영체제에서 실행되는 서비스
    → 클라이언트의 명령(Docker 구현의 제어 센터 역할을 함)을 사용하여, 사용자 대신 Docker 이미지를 작성하고 관리

2. 준비

Docker Hub 가입

  1. Docker Hub 는 Github 처럼 remote 저장소를 활용할 수 있는 곳이다.

  2. 로그인 → Create Repository → Repository 를 생성

  3. repository명 설정 → public → create

3. 개발 및 배포

1) Docker 의 기본적인 흐름

  • "Docker 를 사용해서 서비스를 운영한다."는 것은 "애플리케이션들을 컨테이너화(Containerizing)했다."는 뜻

  • 어플리케이션에 필요한 미들웨어도 컨테이너로 받아서 사용

  • 어플리케이션에 필요한 모든 요소들을 컨테이너로 받고,
    Docker-compose, Docker Swarm, Kubernetes 등...을 이용해서 관리할 수 있다.

  • 애플리케이션을 컨테이너화 했을 때, 개발과 배포의 흐름이 간단해져서 빠르게 진행될 수 있다.

  • 서버의 운영체제나 미들웨어의 의존성에 대해 걱정할 필요없이,
    Docker 만 설치되어 있다면 모든 것이 해결된다.

2) Docker 로 Spring 프로젝트 배포

(1) SpringBoot 프로젝트 생성하기

  1. spring initializr 에서 다음과 같은 설정으로 SpringBoot Application 을 생성

  2. 바탕 화면에 해당 프로젝트 파일을 저장할 폴더 생성

  3. 프로젝트의 기본 구조

(2) 코드 작성

  1. DockerController

    @RestController
    public class DockerController {
    
        @GetMapping("/")
        public ResponseEntity<String> hello(){
            return ResponseEntity.ok("Hello Docker-Spring World!");
        }
    }
  2. DemoApplication 실행

    @SpringBootApplication
    public class DemoApplication {
    
        public static void main (string[] args) {
            SpringApplication.run(DemoApplication.class, args);
            }
    }

  3. localhost:8080 로 연결이 잘 되는지 확인
    1) http://localhost:8080/ 로 접속
    2) 다음과 같은 메시지가 뜬다면 성공

(3) Jar 파일 만들기

Jar 파일은 여러 개의 클래스 파일들과 관련 리소스 및 메타 데이터를 하나의 파일로 모아서, 배포를 위해 만들어진 소프트웨어 패키지 파일 포맷이다.
(Jar 은 zip으로 이루어진 압축 파일)

  1. Gradle 로 들어가기

  2. Tasks → build → bootjar 클릭하기

  3. bootjar 를 클릭하면, 프로젝트 폴더 → build → libs 에 jar 파일이 만들어진다.

(4) DockerFile 작성(추가)

Jar 파일이 있는 곳에 Dockerfile 을 만든다.

  1. # 기반이 되는 이미지를 의미 →  jdk 버전을 명시해주면 된다.
    	# jdk11 버전을 이용해서, Docker 를 올리겠다.
    FROM openjdk:11-jdk
    
    # 컨테이너 내에서 사용할 수 있는 변수를 지정 → JAR 파일의 위치를 환경변수의 형태로 선언
    	# JAR_FILE 변수를 정의 
      # 프로젝트를 빌드할 시, build/libs/xxxx.jar 의 형태로 jar file이 생성되고, 그 파일의 위치를 변수로 저장하는 것
      # 기본적으로 jar file이 2개이기 때문에 이름을 특정해야함
    ARG JAR_FILE=./build/libs/DevopsTestKotlin-0.0.1-SNAPSHOT.jar
    
    # JAR 파일 메인 디렉토리에 복사
    	# 프로젝트의 jar 파일 위치를 참조하여 jar 파일을 가져와서(ARG의 JAR_FILE 변수), 컨테이너의 루트 디렉토리에 app.jar의 이름으로 복사
    COPY ${JAR_FILE} app.jar
    
    # 시스템 진입점(컨테이너가 시작됐을 떄 실행할 스크립트) 정의
        # Docker파일이 Docker엔진을 통해서 컨테이너로 올라갈 때, Docker 컨테이너의 시스템 진입점이 어디인지를 선언
        # java -jar 명령어를 이용해서, 컨테이너의 루트에 위치한 app.jar을 실행하라.
    ENTRYPOINT ["java","-jar","/app.jar"]
  2. git commit and push 를 통해, ec2에 코드 옮겨주기

(5) Docker Image 생성

  1. 터미널 → jar 파일 (cd build/libs 명령어로도 갈 수 있다)

  2. Image 생성 (한 칸 띄고 점을 찍어주는 것에 주의!)

    docker build -t [도커허브ID/레포지토리 이름] .
  3. Image 생성됐는지 확인

    docker images

  4. 만든 repository에 push

    docker push [도커 허브 ID/레포지토리명]

(6) Docker Container 실행

  1. docker run <도커이미지명> 을 통해, container 를 실행시킬 수 있다.

    단, 여기서 8080포트로 진입은 불가능하다.
    → 이미지 기반으로 만든 컨테이너 안에서의 8080포트 이지, localhost의 8080포트를 사용하는 것이 아니기 때문.

  2. 이를 해결하기 위해서는 Port Mapping (포트 맵핑)이 필요

    docker run -p 8080:8080 dockertestimg 로 컨테이너의 Port 를 호스트 시스템의 Port 에 바인딩해준다.

  3. 확인 하기


EC2 환경설정

  1. EC2 생성

  2. ec2 업데이트 & git 설치

    # ec2 업데이트
    sudo yum update -y
    # git 설치하기
    sudo yum install git
  3. jdk를 설치

    # aws coreetto 다운로드
    sudo curl -L https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.rpm -o jdk11.rpm
    
    # jdk11 설치
    sudo yum localinstall jdk11.rpm -y
    
    # jdk version 선택
    sudo /usr/sbin/alternatives --config java
    
    # java 버전 확인
    java --version
    
    # 다운받은 설치키트 제거
    rm -rf jdk11.rpm
  4. java --version 을 통해, 환경설정이 제대로 됐는지 확인

    openjdk 11.0.15 2022-04-19 LTS
    OpenJDK Runtime Environment Corretto-11.0.15.9.1 (build 11.0.15+9-LTS)
    OpenJDK 64-Bit Server VM Corretto-11.0.15.9.1 (build 11.0.15+9-LTS, mixed mode)

    이렇게 뜬다면 성공한 것

Docker-compose 작성(추가)

  1. Docker 의 버전 확인

    sudo yum install docker
    
    # 잘 설치가 되었는지 확인
    sudo docker --version
    Docker version 20.10.7, build f0df350

    이렇게 뜬다면 정상

  2. docker-compose를 설치

    sudo curl -L "https://github.com/docker/compose/releases/download/1.28.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose
    sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
  3. docker-compose 의 버전 확인

    docker-compose --version
    docker-compose version 1.28.2, build 67630359

    이렇게 뜬다면 정상

  4. docker-compose.yml을 프로젝트의 루트 디렉토리에 생성하고, 다음과 같이 작성

    version: "3"
    services:
      web:
        # nginx 이미지의 경우, 인바운드로 들어오는 80번 포트를 docker container 내부에 꽂히는 80번 포트로 포워딩해주는 기능을 수행
        # Http 요청을 nginx 내부로 그대로 흘릴 것이다.
        image: nginx
        ports:
          - 80:80
    
        # volumes 를 통해서, ec2 에 있는 nginx 설정 파일을 컨테이너의 /etc/nginx/conf.d 폴더로 옮겨서 실행  
        volumes:
          - ./nginx/conf.d:/etc/nginx/conf.d
    
        # nginx가 실행되는 시점은 spring 이 컨테이너로 올라간 다음에 올리겠다. 
        depends_on:
          - spring
    
      # 현재 디렉토리에 있는 Docker image 를 빌드시키고, 8080번 포트로 인바운드 들어오는 신호를 컨테이너 내부의 8080번 포트로 그대로 꽂아주겠다.    
      spring:
        build: .
        ports:
          - 8080:8080
  5. nginx 의 설정 파일인 conf.d 를 작성
    1) nginx/conf.d 폴더 내부에 app.conf를 생성

    mkdir nginx
    mkdir nginx/conf.d
    cd nginx/conf.d
    sudo vim app.conf

    2) app.conf 에는 다음과 같이 작성

    server {
        # nginx 이 외부의 80번 포트의 신호를 읽어낸다.
        listen 80;
        access_log off;
    
        location / {
            proxy_pass http://spring:8080;		# 신호를 pass 시킬때는 spring의 8080번 포트로 포워딩시켜서 패스시킨다.
            proxy_set_header Host $host:$server_port;
    
            # proxy에 header를 채우는 코드
            proxy_set_header X-Forwarded-Host $server_name;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

    이렇게 포워딩 된 신호는 spring 입장에서는 인바운드에 해당하므로,
    위에서 '4. docker-compose.yml' 을 작성한대로 spring 은 그에 해당하는 신호를 8080번 포트로 포워딩시켜서 container 내부로 꽂아버린다.

프로젝트 올리기

  1. 프로젝트 빌드시키기

    # gradlew의 권한 변경
    sudo chmod + ./gradlew
    
    # 빌드
    ./gradlew build
  2. docker 실행

    sudo systemctl start docker
  3. docker가 정상적으로 동작하고 있는지 확인

    systemctl status docker
    ● docker.service - Docker Application Container Engine
       Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
       Active: active (running) since 수 2022-04-20 17:48:42 UTC; 51s ago
         Docs: https://docs.docker.com
      Process: 3380 ExecStartPre=/usr/libexec/docker/docker-setup-runtimes.sh (code=exited, status=0/SUCCESS)
      Process: 3379 ExecStartPre=/bin/mkdir -p /run/docker (code=exited, status=0/SUCCESS)
     Main PID: 3384 (dockerd)
        Tasks: 8
       Memory: 119.3M
       CGroup: /system.slice/docker.service
               └─3384 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-ulimit nofile=32768:65536

    이렇게 뜬다면 정상

  4. docker-compose 를 통해서, 프로젝트 올리기

    # docker-compose를 백그라운드에서 동작시키기
    docker-compose up --build -d
    Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/
    Creating network "order-example-kotlin_default" with the default driver
    Building spring
    Sending build context to Docker daemon  45.52MB
    Step 1/4 : FROM openjdk:11-jdk
    11-jdk: Pulling from library/openjdk
    6aefca2dc61d: Pulling fs layer
    967757d56527: Pulling fs layer
    c357e2c68cb3: Pulling fs layer
    c766e27afb21: Pulling fs layer
    a747e81e6111: Pulling fs layer
    2859d18181fd: Pulling fs layer
    3c6d59134c80: Pulling fs layer
    c766e27afb21: Waiting
    a747e81e6111: Waiting
    3c6d59134c80: Waiting
    2859d18181fd: Waiting
    c357e2c68cb3: Verifying Checksum
    c357e2c68cb3: Download complete
    967757d56527: Verifying Checksum
    967757d56527: Download complete
    6aefca2dc61d: Verifying Checksum
    6aefca2dc61d: Download complete
    a747e81e6111: Verifying Checksum
    a747e81e6111: Download complete
    2859d18181fd: Verifying Checksum
    2859d18181fd: Download complete
    c766e27afb21: Verifying Checksum
    c766e27afb21: Download complete
    3c6d59134c80: Verifying Checksum
    3c6d59134c80: Download complete
    6aefca2dc61d: Pull complete
    967757d56527: Pull complete
    c357e2c68cb3: Pull complete
    c766e27afb21: Pull complete
    a747e81e6111: Pull complete
    2859d18181fd: Pull complete
    3c6d59134c80: Pull complete
    Digest: sha256:95b2daeb07a18121a4309a053ff99aa741888528e5da068beef36db092a03e25
    Status: Downloaded newer image for openjdk:11-jdk
     ---> e67a33049aa6
    Step 2/4 : ARG JAR_FILE=./build/libs/DevopsTestKotlin-0.0.1-SNAPSHOT.jar
     ---> Running in a1ebd6481830
    Removing intermediate container a1ebd6481830
     ---> e448756e884e
    Step 3/4 : COPY ${JAR_FILE} app.jar
     ---> 1c1a9cfead2f
    Step 4/4 : ENTRYPOINT ["java","-jar","/app.jar"]
     ---> Running in 7dfbfc10fc7e
    Removing intermediate container 7dfbfc10fc7e
     ---> e1bfd62d0398
    Successfully built e1bfd62d0398
    Successfully tagged order-example-kotlin_spring:latest
    Pulling web (nginx:)...
    latest: Pulling from library/nginx
    1fe172e4850f: Pull complete
    35c195f487df: Pull complete
    213b9b16f495: Pull complete
    a8172d9e19b9: Pull complete
    f5eee2cb2150: Pull complete
    93e404ba8667: Pull complete
    Digest: sha256:694f2ecdb88498325d70dbcb4016e90ab47b5a8e6cd97aaeec53f71f62536f99
    Status: Downloaded newer image for nginx:latest
    Creating order-example-kotlin_spring_1 ... done
    Creating order-example-kotlin_web_1    ... done
  5. 정상적으로 동작하고 있는지 확인


Docker 중 오류가 발생한다면 참고하기


참고: [Docker] Docker의 개념 및 핵심 설명
참고: [Docker] Docker File을 이용하여 Docker Image만들기
참고: [Docker] Private Docker Registry 구축하기
참고: [Docker] Docker 설치부터 실행까지 기본 사용법 정리
참고: Docker
참고: 레거시(legacy)란?
참고: Docker란 무엇인가? 왜 사용할까?
참고: 도커(Docker)란? – 필요성
참고: [Docker] Spring 프로젝트를 Docker를 이용해서 배포해봅시다
참고: Spring Boot, Dockerfile로 이미지 생성, 배포하기
참고: [Docker] - (3) 도커를 사용하여 간단한 SpringBoot 어플 실행하기
참고: [Docker] 스프링부트를 docker 이미지를 통해서 AWS EC2에 배포하기(DockerHub)
참고: Spring Boot + Docker로 배포하기
참고: Docker - 도커에 Spring Boot(Gradle) 구축하기
참고: [Docker] - Spring Boot 애플리케이션을 Docker 이미지로 빌드후 실행해보기

profile
개발자로 거듭나기!

0개의 댓글