학습목표

Spring Boot + MySQL 을 결합해서 실행시키는 것이 목표임.

(이때는 SpringBoot에 Mysql의 URL, ID, PW, PORT 정보가 필요하다.)

 

도커의 특성 리마인드 & 내부 네트워크의 장점

도커의 특성으로 JDK와 MySQL이 로컬에 설치되어있지 않아도 해당 Image를 다운로드 받아서 실행시켜버리면 되니까 매우 편리하다.

또한 도커 내부 네트워크를 만들어서 SpringBoot와 MySQL을 묶어놓으면 두 개의 독립적인 컨테이너는 서로 통신이 가능하게 된다.

외부 Volume을 만들어서 MySQL에 연결하여 MySQL Container와 독립적으로 작동하도록 해놓는 것도 잊지말자.

 

 

학습 준비

실습 디렉토리 : ex08

스프링 부트 GIT : git clone https://github.com/codingspecialist/docker-test-server.git

※ 우분투에서 처음 git clone을 했다면 로그인하라고 뜨는데 github id는 그대로 쓰고, pw는 personal token을 발급받아서 복사해주면 된다.

(settings > (사이드 메뉴의 맨마지막) Developer Settings > Personal access toekns)

 

1. docker-test-server  (Spring Boot)

 

[SpringBoot Server Dockerfile 작성] ( ~ex08/docker-test-server 디렉토리에 작성)

FROM openjdk:11-jdk-slim

WORKDIR /app

# COPY만 docker-compose 파일의 위치를 기반으로 작동함
# docker-test-server내부에 있는 모든 파일을 WORKDIR인 /app으로 COPY를 한다는 의미이다.
COPY . .

# RUN은 현재 파일의 위치를 기반으로 작동함
RUN chmod +x ./gradlew
RUN ./gradlew clean build

# build.gradle에 어떤 설정을 하면 .jar파일이 1개가 만들어진다. (원래는 2개만들어짐)
# 만들어진 jar파일의 이름을 app.jar 로 변경한다는 의미이다. (실행하기 편하게)
#ARG JAR_FILE=build/libs/*.jar
#COPY ${JAR_FILE} app.jar

# 로컬에 빌드된게 아니라 컨테이너 내부에서 빌드된거니까 위에있는 COPY를 쓰면 안되고 RUN으로 실행시켜
야한다.
ENV JAR_PATH=/app/build/libs
RUN mv ${JAR_PATH}/*.jar /app/app.jar

ENTRYPOINT ["java", "-jar","-Dspring.profiles.active=prod","app.jar"]

주석처리된 내용 중에 #build.gradle에 어떤 설정을하면 .jar파일이 1개만 만들어진다는 내용이 있는데

git clone받은 파일 중 build.gradle 내용 맨 마지막 내용을 보면

jar {
        enabled = false
}

이러한 내용이 있다. 해당 내용이 "프로젝트명-버전-plain.jar" 파일을 생성하지 않고 즉시 실행가능한 executable.jar파일("프로젝트명-버전.jar")만 생성 하게 하는 옵션이다. 해당 옵션을 사용하지 않으면 plain.jar, executable.jar 두개의 파일이 생성된다.

관련링크 : https://dev-j.tistory.com/22

 

Plain jar vs Executable jar(feat. plain jar 생성 방지)

스프링 부트 gradle 플러그인 2.5 버전부터 gradle 빌드 시 JAR 파일이 2개 생성된다. 별도의 설정을 하지 않았을 때 하나는 "프로젝트 이름-버전.jar", 다른 하나는 "프로젝트 이름-버전-plain.jar"이라는

dev-j.tistory.com

 

2. docker-test-db (MySQL)

아래의 내용들은 ~ex08/docker-tset-db 디렉토리에 작성 해야한다.

 

[init.sql 작성] 

init.sql은 Docker Container가 실행될 때 자동으로 해당 SQL을 실행시켜 DB 초기화를 진행시키기 위한 파일이다. (컨테이너를 내렸다가 다시 올려도 실행되는지는 확인해봐야함!)

CREATE TABLE user_tb(
        id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO user_tb (name) VALUES ('John');
INSERT INTO user_tb (name) VALUES ('Jane');

 

[MySQL Dockerfile 작성] 

FROM mysql:8.0

#docker-entrypoint-initdb.d로 복사 해준 sql은 자동으로 실행된다. (문서에 나와있다고함)
COPY init.sql /docker-entrypoint-initdb.d

ENV MYSQL_ROOT_PASSWORD=root1234
ENV MYSQL_DATABASE=metadb
ENV MYSQL_HOST=%

CMD ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]

 

 

3. docker-compose.yml 작성

docker-compose.yml파일은 ~ex08/docker-compose.yml 에 작성해주면 된다.

version: '3'

services:
  db:
    build:
      #context = Dockerfile의 위치-이걸 안잡아주면 COPY할 때 init.sql위치를 ex08(docker-compose.yml이 있는 곳)으로 봐버리는 문제가 생긴다.
      context: ./docker-test-db 
      dockerfile: Dockerfile
    ports:
      - 3306:3306
    volumes:
      - ./docker-test-db/store:/var/lib/mysql
    networks:
      - network

  server:
    build:
      context: ./docker-test-server
      dockerfile: Dockerfile
    restart: always
    ports:
      - 8080:8080
    depends_on:
      - db #db가 먼저 구축되고 나서 다 되면 server를 실행시키는 것을 의미한다.
    environment: #해당 값들은 application-prod.yml에서 ${SPRING_DATASOURCE_URL} 에서 사용한다.
      SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/metadb?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_DRIVER: com.mysql.cj.jdbc.Driver
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: root1234
    networks: #동일 네트워크로 잡아주어야 datasource url에서 jdbc:mysql://db 로 쓸수있는 것이다. ip 로 안쓰고..
      - network

networks:
  network:

db쪽에서 init.sql 을 실행시킬 때 강사님은 Dockerfile에서 "/docker-entrypoint-initdb.d" 경로로 COPY를 하였지만 다른 분은 docker-compose.yml에서

volumes:

  - "./init/:/docker-entrypoint-initdb.d/" 

이런식으로 하신분들도 있다.

 

4. 컨테이너 실행

docker compose up -d --build

docker compose up -d --build 를 해주면 다시 이미지까지 빌드된다. 

 

실습 디렉토리 : ex07/composetest

튜토리얼 사이트 : https://docs.docker.com/compose/gettingstarted/

 

Docker Compose Quickstart

Check out this tutorial on how to use Docker Compose from defining application dependencies to experimenting with commands.

docs.docker.com

3단계 까지만 진행했음.

 

1. 프로젝트에 대한 디렉토리를 만듭니다.

$ mkdir composetest
$ cd composetest

 

2. app.py프로젝트 디렉토리에 라는 파일을 만들고 다음 코드를 붙여넣습니다.

vi app.py

import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)

 

3. 프로젝트 디렉토리에 requirements.txt  파일을 만들고 다음 코드를 붙여넣습니다.

vi requirements.txt

flask
redis

 

 

4. 코드를 생성하여 Dockerfile다음 코드를 붙여넣으세요.

# syntax=docker/dockerfile:1
FROM python:3.10-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run", "--debug"]

 

이는 Docker에게 다음을 알려줍니다.

  • Python 3.10 이미지로 시작하여 이미지를 빌드합니다.
  • 작업 디렉토리를 .으로 설정합니다 /code.
  • 명령 에 사용되는 환경 변수를 설정합니다 flask.
  • gcc 및 기타 종속성 설치
  • requirements.txtPython 종속성을 복사 하고 설치합니다.
  • 컨테이너가 포트 5000에서 수신 중임을 설명하는 메타데이터를 이미지에 추가합니다.
  • .프로젝트의 현재 디렉토리를 .이미지의 작업 디렉토리로 복사합니다.
  • 컨테이너의 기본 명령을 .으로 설정합니다 flask run --debug.

 

5. docker-compose.yml 정의

services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"
  • 이 web서비스는 현재 디렉토리에 있는 Dockerfile이 빌드된 이미지를 사용합니다 
  • 그런 다음 컨테이너와 호스트 머신을 노출된 포트인 에 바인딩합니다. (8000(HOST) --> 5000(Container)) 5000포트는 flask의 기본 포트임.

6. 컨테이너 실행

docker compose up -d

 

H2 server에 접속해보면 잘 작동하는 것을 볼 수 있다.

redis에 잘 연결되어있으면 새로고침 할 때 마다 카운트가 올라감.

 

H2 server에 올라간 container flask에 접속한 화면

 

compose watch 부분은 강의 때 안 다뤄서 하지않았음. 필요하면 개인적으로 공부해야할듯!

작업 디렉토리 : ex06_docker_compose

 

도커 컴포즈는 다중 컨테이너 Docker 애플리케이션을 정의하고 실행하기 위한 도구이다.

YAML파일을 사용하여 서비스를 구성한다.

  • 서비스 시작, 중지 및 다시 구축
  • 실행 중인 서비스 상태 보기
  • 실행 중인 서비스의 로그 출력 스트리밍
  • 서비스에서 일회성 명령 실행

기존 Dockerfile 방식

Dockerfile은 다중 컨테이너를 실행할 때 매우 번거롭다. 각각 컨테이너들 간의 요청 응답을 위해  IP, PORT 설정 다 잡아줘야하고 따로따로 Dockerfile 을 만들어 줘야한다.

 

도커 컴포즈를 사용하면 컨테이너간의 유기적 결합을 손쉽게 해결 할 수 있다.

이번 시간에는 1개의 컨테이너만 도커 컴포즈로 실행해본다.

 

1. docker-compose.yml 파일 생성

version: '3.8'
services:
  mysqldb:
    image: mysql:latest
    restart: always
    volumes:
      - mysql-compose-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_HOST: "%"
      MYSQL_ROOT_PASSWORD: root1234
      MYSQL_DATABASE: rootdb
    ports:
      - "3307:3306"
    networks:
      - docker_default
volumes:
  mysql-compose-volume:

 

2. docker-compose 실행하기

docker-compose up -d

위의 명령어로 실행하면 아래와 같은 오류발생! 이유는 버전이 안맞아서 그런거 같다. (최신 docker-compose는 명령어도 다름)

 

 

최신 문법은 아래와 같다.

 docker compose up -d

 

3. docker-compose로 실행된 컨테이너 확인하기

docker compose ps

 

4. DB 접속기로 접속해보기

문제발생! 접속기로 접속이 안된다. 확인해보니까 docker compose up -d 로 실행할 때 default-network가 자동으로 만들어지던데 그거 때문 인것 같다.

 

 

일단 docker compose down 으로 컨터이너와 network를 지워주자.

 

networks 부분을 추가해주자. (services, networks)

external: true 를 하면 기존에 있는 것을 사용하겠다는 의미. 해당 부분을 추가하지 않으면 계속 새로운 네트워크를 생성해댄다.

version: '3.8'
services:
  mysqldb:
    image: mysql:latest
    restart: always
    volumes:
      - mysql-compose-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_HOST: "%"
      MYSQL_ROOT_PASSWORD: root1234
      MYSQL_DATABASE: rootdb
    ports:
      - "3307:3306"
    networks:
      - docker_default
volumes:
  mysql-compose-volume:
networks:
  docker_default:
    external: true

 

하지만 네트워크를 default로 바꾸어봐도 호스트OS의 DB접속기에서는 여전히 접속이 불가능했다.

 

 

문제해결) 문제원인은 네트워크가 아니라 원격 유저 설정이 되지 않았기 때문이었다.

docker exec -it [CONTAINER ID] bash

컨테이너 OS 접속 후

mysql을 입력 하면 mysql로 접속되는데 접속 후 아래 명령어를 입력하여 원격 유저를 만들어 주면 된다.

mysql> create user 'root'@'%' identified by 'root1234';
Query OK, 0 rows affected (0.04 sec)

mysql> grant all on *.* TO root@'%';
Query OK, 0 rows affected (0.02 sec)

 

꼭 컨테이너에 접속해서 할 필요는 없었다..

docker-compose.yml 에서 environments에 MYSQL_ROOT_HOST를 "%" 로 설정해주면 된다.

이렇게 하면 이제 DB접속기에 문제없이 접속가능할 것이다.

 

아래와 같은 쿼리문을 입력하자.

USE rootdb;

CREATE TABLE person(
	id INT PRIMARY KEY, 
	NAME VARCHAR(100)
);

INSERT INTO person(id, NAME) VALUE(1, 'ssar');
INSERT INTO person(id, NAME) VALUE(2, 'ssar2');

SELECT * FROM person;

 

컨테이너를 종료(docker compose down) 하고 다시 실행(docker compose up -d) 해도 person 테이블의 데이터가 살아있는 것을 확인 하면 이번 실습은 끝!

 

컨테이너 환경변수(environments) 다른걸로 만들 때 볼륨까지 지워야하는거 잊지 말자..

docker volume lsdocker volume rm [VOLUME NAME]

환경변수 : OS에서 사용하는 변수

 

1. 목표

  • MySQL 컨테이너를 설치 (OS는 우분투)
  • MySQL 컨테이너가 설치된 OS에 환경변수를 설정
  • MySQL에서 설정된 환경변수를 사용

2. 작업 디렉토리 위치 (ex05)

/docker/docker_files/lecture/docker_lab/ex05

 

3. 도커파일 생성, 빌드 및 컨테이너 생성

FROM mysql

ENV MYSQL_USER=ssar
ENV MYSQL_PASSWORD=ssar1234
ENV MYSQL_ROOT_PASSWORD=root1234
ENV MYSQL_DATABASE=ssardb

CMD ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]

마지막의 CMD는 캐릭터셋을 UTF-8로 설정하기 위함.

 

도커파일 빌드하기

docker build -t mysql-images ./

 

MYSQL 컨테이너 생성

docker run -d -p 3307:3306 --name mysql-container mysql-images

mysql은 기본 3306포트를 사용하는데 3307로 요청이오면 3306으로 포트포워딩 해주자.

 

4. DB접속기로 검증하기(DBeaver, SQL yog, Mysql Bench 등)

컨테이너가 제대로 실행된 것을 확인했다면 DB 접속기로 잘 접속되는지 확인해보자.

나는 SQL Yog를 사용함~

IP와 Dockerfile에서 설정한 MYSQL_USER, MYSQL_PASSWORD에 입력한 부분을 입력하고 포트로 3307(3306으로 포워딩)을 입력 후 테스트 연결에 성공하면 끝!

 

UTF-8 설정이 제대로 되었는지 SQL yog에서 아래의 SQL문을 실행시켜보자.

 SHOW VARIABLES LIKE 'character_set_%';

value가 utf8mb3 가 나오면 된다.

 

5. 환경변수 확인하기

Dockerfile에서 ENV 로 설정한 OS 환경변수가 제대로 설정되었는지 알아보기 위해 mysql 컨테이너에 접속해보자.

docker exec -it [CONTAINER ID] bash

 

터미널에 정상적으로 접속 되었다면 아래의 명령어를 입력하여 Dockerfile에서 ENV 명령어로 설정한대로 값이 제대로 나오는지 확인하면 된다.

echo $MYSQL_USER
echo $MYSQL_PASSWORD

 

6. Mysql 볼륨

mysql 컨테이너는 자동으로 볼륨을 하나 사용한다. Mysql의 데이터가 해당 볼륨에 저장되는데 문제는 컨테이너가 재실행되면 같은 볼륨을 사용하는 것이 아니라 기존 볼륨을 삭제 후 새로운 볼륨이 생성되어버린다. 그래서 기존 데이터는 모두 지워지게 된다.

 

첫 번째 해결책

이 문제를 해결하기 위해서는 2가지 해결책이있는데 그 중 첫 번째는 HOST에 볼륨을 연결하면 된다.

이는 docker hub의 mysql 공식 사이트에도 있는 내용이다.

 

볼륨연결을 위한 호스트OS에 디렉토리 만들기

디렉토리명: mysql-volume

/docker/docker_files/lecture/docker_lab/ex05/mysql-volume

mkdir mysql-volume

 

 

볼륨 옵션으로 호스트 디렉토리 연결하여 실행

docker run -d -p 3307:3306 -v /home/docker/docker_files/lecture/docker_lab/ex05/mysql-volume:/var/lib/mysql --name mysql-container mysql-images

 

정상적으로 실행 되었다면 mysql-volume 디렉토리에 들어가보면 각종 데이터 파일들이 있는 것을 볼 수 있다.

 

두 번째 해결책

이름이 있는 볼륨 생성하여 실행하기 

위에서 실습했던 내용을 초기화 후 진행 (remove.sh)

 

이 방법은 귀찮게 따로 디렉토리를 만들어도 되지 않아도 되고 그냥 -v 옵션에서 이름만 설정해주면 된다!

docker run -d -p 3307:3306 -v mysql-test-volume:/var/lib/mysql --name mysql-container mysql-images

 

해당 방법으로 실행하면 볼륨을 보는 명령어로 보면 볼륨이 생성된 것을 확인할 수 있다.

docker volume ls

 

이름있는 볼륨 으로 만들었을 때 데이터가 제대로 보관되는지 검증하기

 USE ssardb;
 
 CREATE TABLE person(
	id INT PRIMARY KEY,
	NAME VARCHAR(100)
 );
 
 INSERT INTO person VALUES (1, 'ssar');
 
 SELECT * FROM person;

1. 이름 있는 볼륨으로 만들어진 컨테이너에 sql yog로 접속해서 위의 sql 문을 차례대로 실행한다.

2. 도커 컨테이너 중지 및 삭제(remove.sh)

3. 아래의 명령어로 다시 컨테이너를 생성

docker run -d -p 3307:3306 -v mysql-test-volume:/var/lib/mysql --name mysql-container mysql-images

4. 다시 sql yog로 새로 생성된 컨테이너에 접속하여 SELECT * FROM person; 실행 후 제대로 나오는지 확인!

18강에서 이어서 하는 내용.

 

1. nginx.conf 수정

lb에 설정한 nginx.conf 내용을 수정하자. IP를 찾는것이 비효율적이므로 서버 IP를 직접 설정하는게 아니라 게이트 웨이 주소로 설정하고 포트번호만 server1, server2 것으로 설정하면 좀 더 효율적이 된다.

upstream server1{
                server 172.17.0.1:8081;
}

upstream server2{
                server 172.17.0.1:8082;
}

server{
        listen 80;
        server_name localhost;

        #여기서 server1은 위의 upstream server1을 의미한다.
        location /server1{
                proxy_pass http://server1/;
        }

        #여기서 server2는 위의 upstream server2를 의미한다.
        location /server2{
                proxy_pass http://server2/;
        }

}

/ex04/lb/conf/nginx.conf

 

프록시를 사용한 로드밸런스는 원래라면 더 많은 설정을 만져야하지만 여기까지만 강의해주신다고 하신다.

또한, 이번에는 docker run을 사용해서 3가지 nginx container를 띄웠지만 docker compose를 배우면 한방에 컨테이너들을 유기적으로 결합해서 띄우는 방법을 배울 수 있다고 하심.

 

 

해당 강의는 ex04 디렉토리에서 진행하였음.

 

1. 디렉토리 및 필요한 파일 생성

  • server1
    • webapp
      • index.html
    • Dockerfile
  • server2
    • webapp
      • index.html
    • Dockerfile
  • lb
    • Dockerfile 
    • conf
      • nginx.conf

Dockerfile (server1, server2 동일)

FROM nginx

COPY ./webapp /usr/share/nginx/html

ENTRYPOINT ["nginx", "-g", "daemon off;"]

 

index.html (server1)

<h1>Welcome nginx Server1</h1>

 

index.html (server2)

<h1>Welcome nginx Server2</h1>

 

 

2. Dockerfile 빌드

ex04 디렉토리에서 진행.

docker build -t server1:1.0 ./server1
docker build -t server2:1.0 ./server2

 

3. Docker 이미지 확인 및 실행

docker images

빌드한 이미지가 제대로 생성되었는지 확인 한다.

 

이미지가 제대로 생성되었으면 아래의 명령어로 실행

docker run -d -p 8081:80 --name nginx-server1 server1:1.0
docker run -d -p 8082:80 --name nginx-server2 server2:1.0

docker ps 및 제대로 실행되었는지 확인하는 부분은 생략!

 

4. 구성하려는 서버 구성도

 

5. 설정파일 생성

lb/conf/nginx.conf 파일을 생성한다.

upstream server1{
                server 172.17.0.3:80;
}

upstream server2{
                server 172.17.0.4:80;
}

server{
        listen 80;
        server_name localhost;

        #여기서 server1은 위의 upstream server1을 의미한다.
        location /server1{
                proxy_pass http://server1/;
        }

        #여기서 server2는 위의 upstream server2를 의미한다.
        location /server2{
                proxy_pass http://server2/;
        }

}

여기서 upstream server1, upstream server2 IP는 docker inspect [CONTAINER ID] 로 확인하여 넣어주어야한다.!!

 

lb용 Dockerfile을 작성한다.

FROM nginx
COPY conf/nginx.conf /etc/nginx/conf.d/default.conf
ENTRYPOINT ["nginx", "-g", "daemon off;"]

 

6. lb 빌드하기

docker build -t lb:1.0 ./lb

 

7. lb 실행하기

docker run -d -p 8080:80 --name nginx-lb lb:1.0

 

8. 로드밸런스 확인하기

192.168.0.3:8080/server1

192.168.0.3:8080/server2 

각각 접속해보고 server1, server2의 index.html 이 뜨면 성공!

 

 

16강에서부터 이어진 내용이므로 ex03/webapp, ex03/conf 디렉토리 생성되어있는 것을 가정한다.

1. Dockerfile 작성

 1 FROM nginx
 2
 3 #COPY webapp /usr/share/nginx/html
 4 #COPY conf/nginx.conf /etc/nginx/conf.d/default.conf
 5
 6 ENTRYPOINT ["nginx", "-g", "daemon off;"]

아직 webapp과 conf에 들어갈 내용이 없으니까 일단 주석 처리 해주자.

 

2. Dockerfile build 및 컨테이너 실행

docker build -t nginx-server ./
docker run -d -p 8080:80 --name some-nginx nginx-server

 

3. default.conf 내용 가져오기

우리가 건드려야할 conf파일을 확인 후 base될 내용을 가져오자.

docker exec -it [CONTAINER ID] bash

실행한 컨테이너의 터미널에 접속한다.

cd /etc/nginx/conf.d

컨테이너의 터미널에 접속했으면 nginx의 default config파일이 있는 곳으로 이동한다.

cat default.conf

 

우리는 default.conf를 base로 하여 설정을 건드려야하므로 해당 내용을 복사해서 만들어둔 호스트의 conf 폴더로 가져오자.

server {
    listen       80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

해당 내용을 복사 → 컨테이너 터미널 종료 → HOST의 conf디렉토리에 nginx.conf 파일을 생성한 후 복사한 내용을 붙여넣기한다.

 

이전 15 RUN명령어 강의에서 기본으로 제공되는 html을 바꾸기 위해서 ./index.nginx-debian.html 이렇게 변경하였는데 그때는 config 파일에 다르게 설정되어있어있어서 그렇다고 하심.

 

4. 기본페이지, 에러페이지 변경하기

우리가 참고할 설정들은 기본 location과 error가 발생했을 때 보여줄 location 이다.

해당 설정을 위해서는 설정파일의 7,17 번째 줄을 변경하면 된다.

에러페이지용 index는 17번째 줄을 보면 50x.html 이름으로 설정되어있고, 기본 location은 index.html로 설정되어있으므로 webapp에 index.html과 50x.html을 생성해준다. (둘다 경로는 /usr/share/nginx/html 로 동일한 것을 볼 수 있다.)

<h1>Error Page!!</h1>

50x.html

<h1>Welcome Nginx!!</h1>

index.html

 

5. Dockerfile 수정 및 재빌드

주석 처리해둔 COPY 명령어 부분을 주석해제 한 후 빌드를 다시 해주자.

  1 FROM nginx
  2
  3 COPY webapp /usr/share/nginx/html
  4 COPY conf/nginx.conf /etc/nginx/conf.d/default.conf
  5
  6 ENTRYPOINT ["nginx", "-g", "daemon off;"]

Dockerfile

 

docker build -t nginx-server:2.0 ./

빌드

 

docker run -d -p 8080:80 --name some-nginx nginx-server:2.0

실행

 

버그발생

docker ps -a  확인 결과 컨테이너가 강제 종료되는 현상

docker logs [CONTAINER ID] : 명령어로 로그를 보니 아래와 같은 로그가 출력되어있었다.

conf에 있는 nginx.conf 에 오타가 나와있어서 수정함!

 

다시 빌드해서 다시 실행시켜 보면 설정한 대로 동작하는 것을 볼 수 있다.

아직 50x 에러를 발생시킬 수 없어서 보여줄 수가 없다.

기본 페이지는 설정한 대로 제대로 뜬다.

 

컨테이너에 터미널로 접속해서 확인해봐도 설정한대로 잘 복사되었다.

설정파일도 제대로 복사된것을 알 수 있다.(/etc/nginx/conf.d/default.conf)

1. 실습준비

그동안의 실습 내용들 모두 정리

nginx, httpd 컨테이너, 이미지 모두 지운 다음 lecture/ex03디렉토리를 생성한다.

 

2. 파일 생성

ex03 디렉토리 안에서 아래와 같이 디렉토리와 Dockerfile을 생성해준다.

mkdir conf
mkdir webapp
touch Dockerfile

 

3. nginx컨테이너 실행

docker run --name some-nginx -d -p 8000:80 nginx

 

4. docker inspect

docker inspect [CONTINAER ID]

nginx의 컨테이너 ID를 입력해서 nginx 컨테이너를 분석해보자.

일단 docker ps로 방금 전에 실행시킨 nginx를 보면 COMMAND가 /docker-entroypoint... 인걸 볼 수 있다.

 

좀 더 자세히 보기 위해서 docker inspect를 사용해서 봐보자. 컨테이너 내부에서 해당 shell 파일을 실행시켜 주는 것 같다.

 

어떤 스크립트인지 컨테이너 내부에서 해당 파일을 찾아보자.

docker-entorypoint.sh는 / 에서 바로 찾아볼 수 있었다.

docker exec -it 32b bash

 

네트워크 정보

컨테이너의 네트워크 정보

여기서 볼건 IPAddress와 Gateway인데 IPAddress는 나중에 다른 컨테이너와 통신이 필요할 때 컨테이너 끼리 내부적으로 데이터를 주고받을 때 필요함. (Spring ↔ MySQL 등등) 근데 아이피 보다는 --name으로 다른 컨테이너를 식별하는게 더 편하다고 하심.

Gateway는 HOST와 연결된 통로라고 생각하면된다.

 

주의 

Dockerfile에 쓰는 EXPOSE 80 같은 명령어는

80포트를 여는 명령어가 아니라 80포트가 열려있음! 이라고 알려주는 표시일 뿐이다.

RUN 

Dockerfile에서 리눅스의 명령어를 실행하고 싶을 때 사용한다.

 

실습1. Dockerfile 작성

  1 FROM ubuntu
  2
  3 RUN apt-get update
  4 RUN apt-get install -y nginx
  5
  6 WORKDIR /var/www/html
  7
  8 COPY ./webapp/index.html ./index.nginx-debian.html
  9
 10 ENTRYPOINT ["nginx", "-g", "daemon off;"]

 

RUN 명령어 실습을 위한 Dockerfile 작성

 

FROM ubuntu

다른 실습과 다르게 ubuntu를 base로 해서 처음부터 설치하는 방식으로 실습하는게 특징. (RUN명령어 실습을 위해서 그러신듯)

 

RUN apt-get update

RUN apt-get install -y nginx

컨테이너 실행될 때 리눅스 명령어를 실행하는 것이다.

 

 

WORKDIR

작업 디렉토리를 파라미터로 넘겨받은 경로로 설정한다. 

COPY, BASH 같은 명령어도 모두 해당 경로부터 시작된다.

 

 

COPY

HOST내용물을 CONTAINER로 복사한다.

(호스트)./webapp/index.html →  (컨테이너) /var/www/html/index.nginx-debian.html 로 복사한다.

 

 

ENTRYPOINT : 컨테이너가 실행될 때 무조건 실행되는 명령어

(ENTRYPOINT는 CMD로 대체가능하다고 하심.)

 

ENTRYPOINT에 쓰인 daemon off;는 중요하다! 백그라운드로 실행하지말고 포그라운드로 실행하라는 의미인데 nginx를 백그라운드로 실행하면 컨테이너가 실행하자마자 죽어버린다고 함. (더 이상 실행할 명령어가 없다고 판단하고...) nginx command인 "nginx -g 'daemon off;'" 가 COMMAND로 떠있어야 죽지않음!

 

실습2. 빌드하기 및 확인하기

작성된 Dockerfile을 기반으로 image를 빌드하자.

docker build -t nginx-server:2.0 ./

docker build -t [생성할이미지명][생성할태그] [Dockerfile 위치] 

 

빌드가 다되었다면 이미지가 생성되었는지 확인하자.

docker images

 

실습3. 빌드된 이미지 실행하기

docker run -d -p 8080:80 nginx-server:2.0

결과확인

1. Dockerfile 작성

FROM openjdk:11-jdk-slim
WORKDIR /app 
COPY build/aws-v3-0.0.3.jar ./application.jar
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev", "application.jar"]
#CMD ["--server.port=8080"]

 

WORKDIR 

  • 모든 작업이 해당 디렉토리에서 진행되도록 처음 시작 디렉토리를 지정.
  • 사용자가 터미널로 접근 했을 때도 /app 디렉토리로 바로 접근된다. (docker attach, docer exec -it ~ bash)
  • COPY와 같이 상대경로로 설정되어있다면 처음 시작지점이 WORKDIR에서 지정한 폴더가 된다.
    (  ./application.jar === /app/application.jar)

COPY (vs ADD)

  • build/aws-v3.0.0.3.jar를 복사하는데 파일명은 application.jar로 변경
  • ADD와의 차이점 : ADD는 압축도 풀린다고함. ADD 압축파일.zip ./ #이렇게 하면 압축풀림

ENTRYPOINT

  • 명령어를 실행해주는 것.
  • CMD와 비슷하다.
  • 파라미터로 넘겨받은 것들을 합쳐서 컨테이너 실행 시 실행시켜 준다.
  • Dockerfile을 빌드해서 컨테이너가 실행되면 java -jar -Dspring.profiles.active=dev application.jar 명령어가 자동으로 실행된다. (물론 /app 디렉토리에서)

ENTRYPOINT vs CMD

  • ENTRYPOINT는 컨테이너가 실행될 때 무조건 실행되는 명령어
  • CMD도 컨테이너가 실행될 때 실행되는 명령어 이지만 외부의 값에 따라서 대체가 가능하다. (옵셔널) CMD는 ENTRYPOINT의 파라미터로 넘겨지기도 한다.
CMD ["--server.port=3000"]

이렇게 해놓아도

docker run -d -p 9097:5000 java-server --server.port=5000

컨테이너를 실행할 때 위와 같이 실행시키면 --server.port=5000 으로 실행된다. (Dockerfile에 있는 CMD 대체)

 

정리하자면 무조건 대체제없이 실행되어야할 것들은 ENTRYPOINT로 실행하면될거같고, 내가 run할 때마다 바꿀수도있는 값은 CMD로 설정해두면 될거같다.

 

2. 실습에 필요한 jar 파일 다운로드

https://github.com/codingspecialist/aws-v3/tree/release

 

GitHub - codingspecialist/aws-v3: elastic bean stalk

elastic bean stalk. Contribute to codingspecialist/aws-v3 development by creating an account on GitHub.

github.com

spring project가 jar로 압축되어있는 파일이다.

해당 파일을 build디렉토리에 넣어주자. (Dockerfile에 COPY build/aws-v3.0.0.3.jar 로 해놨으니까.)

2. Dockerfile build

docker build -t java-server:1.0 ./

docker build -t [생성할이미지명][생성할태그] [Dockerfile 위치] 

3. Docker image확인

docker images

빌드 결과가 제대로 생성되었는지 이미지를 확인해주자.

 

4. 컨테이너 실행

docker run -d -p 9097:8081 java-server:1.0

 

현재는 Dockerfile의 CMD 명령어가 없어서 spring.profiles.active=dev가 실행되어 8081이 기본포트로 잡힌다.

(ENTRYPOINT로 -Dspring.profiles.active=dev 를 설정하였기 때문에.)

 

만약에 Dockerfile에 CMD를 추가한다면?

FROM openjdk:11-jdk-slim
WORKDIR /app 
COPY build/aws-v3-0.0.3.jar ./application.jar
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev", "application.jar"]
CMD ["--server.port=8080"]

이렇게 되면 8080 포트가 잡힌다. java -jar -Dspring.profiles.active=dev application.jar --server.port=8080 이라는 명령어가 실행된 것과 같기 때문에.

 

근데 Dockerfile에도 추가하고 run 옵션으로도 추가하면? run옵션으로 추가한 것이 Dockerfile의 CMD 명령어를 대체한다.

docker run -d -p 9097:8800 java-server:1.0 --server.port=8800

이렇게 되면 spring의 내장 tomcat은 8800으로 실행된다.

 

5. 컨테이너 로그 확인

컨테이너 내부의 로그를 보기 위해서는 아래와 같은 명령어로 확인한다.

docker logs [CONTAINER ID]

+ Recent posts