본문 바로가기
Docker

[Docker] 도커로 로컬 서버 배포하기

by 그리득 2024. 4. 8.
728x90

로컬 환경에서 Docker 실행

• 참고 문헌 : https://www.docker.com/blog/kickstart-your-spring-boot-application-development/

 

Kickstart Your Spring Boot Application Development | Docker

Learn from Docker experts to simplify and advance your app development and management with Docker. Stay up to date on Docker events and new version

www.docker.com

  • docker run -p 8080:8080 -t spring-helloworld
  • docker run -d -p 8080:8080 -t spring-helloworld

docker run을 통해 새로운 컨테이너를 생성하고 시작해줍니다. ( -d는 백그라운드에서 실행)

터미널 로그에 Spring 문양이 뜬다면 성공.

docker desktop에서 실행

도커 데스크탑에서도 컨테이너가 생성된 것을 확인할 수 있습니다.

8080포트를 통해 홈페이지 연결까지 확인.

docker desktop에서 log 확인해보기

 

DockerFile 작성하기

DockerFile란?

- 도커 이미지를 구축하기 위해 명령어들을 순차적으로 나열한 텍스트 파일

- 각각의 명령어는 이미지의 새로운 계층을 만들어 내며, 이러한 계층들이 합쳐져 최종적인 이미지를 형성

 

Dockerfile 작성의 기본 구조와 주요 명령어

# 1단계: Maven 또는 Gradle을 사용하여 Spring Boot 애플리케이션 빌드
FROM maven:3.6.3-jdk-11 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn -f pom.xml clean package

JAR 파일을 실행하기 위한 새로운 레이어

FROM openjdk:11
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

1. Maven 기반 이미지를 사용하여 소스 코드를 컨테이너 내부로 복사하고, Maven을 사용해 애플리케이션을 빌드
2. OpenJDK 기반 이미지를 사용하여 빌드 단계에서 생성된 JAR 파일을 복사하고, Java 애플리케이션을 실행

### 기본 구조 및 명령어

1. **FROM**: 기반 이미지를 지정한다.
모든 `Dockerfile`은 `FROM` 명령어로 시작해야 하며, 이는 빌드 과정의 기점이 되는 이미지를 정의한다.
   ```dockerfile
   FROM ubuntu:18.04
 

1.  LABEL: 이미지에 메타데이터를 추가 (이미지의 제작자 정보를 포함)

명령어 예시) LABEL maintainer="name@example.com"

 

2. RUN: 이미지 빌드 과정 중에 명령어를 실행. 주로 패키지 설치나 설정 파일 변경에 사용된다.

RUN apt-get update && apt-get install -y python

 

3. COPY: 호스트의 파일이나 디렉토리를 이미지 내부로 복사. 애플리케이션의 소스 코드를 이미지에 추가할 때 주로 사용된다.

COPY . /app


4. ADD: COPY 명령어와 유사하지만, 원격 URL에서 파일을 추가하거나 로컬의 압축 파일을 압축 해제하며 파일을 추가할 수 있다.

ADD https://example.com/big.tar.xz /usr/src/things/

 

5. CMD: 컨테이너가 시작될 때 실행할 기본 명령어를 정의. Dockerfile 내에서 한 번만 사용할 수 있다.

CMD ["python", "./app/app.py"]

 

6. EXPOSE: 컨테이너가 리스닝할 포트를 지정. 네트워킹 구성에 도움을 준다.

EXPOSE 80

 

7. ENV: 환경 변수를 설정. 애플리케이션 설정에 사용된다.

ENV API_KEY="YOUR_API_KEY"

 

8. WORKDIR: RUN, CMD, ENTRYPOINT, COPY, ADD 명령어가 실행될 작업 디렉토리를 설정.

WORKDIR /app

 

9. ENTRYPOINT: 컨테이너가 시작될 때 실행할 명령어를 설정. CMD와 함께 사용되어 애플리케이션의 실행 방식을 정의할 수 있다.

ENTRYPOINT ["python"] CMD ["app.py"]

 

정리

- Dockerfile을 준비한 후에는 docker build 명령어를 통해 이미지를 빌드할 수 있다. 이때 Dockerfile 내의 지시어들이 순서대로 실행되어 최종 이미지가 생성된다.

- Dockerfile을 활용함으로써 애플리케이션의 빌드와 배포 과정을 표준화하고 자동화할 수 있으며, 이는 개발의 효율성을 높이는 데 기여한다.

 

도커 이미지 최적화

도커 이미지의 크기를 줄이기 위한 Dockerfile 최적화 전략에는 여러가지 방법이 있다. 이미지의 효율성을 높이고, 배포 시간을 단축하며, 보안을 강화하는 데 중요하다. 여기 몇 가지 핵심 전략과 멀티 스테이지 빌드에 대한 설명을 추가하겠다.

 

1. 경량 베이스 이미지 사용

  • 가능한 가장 경량의 베이스 이미지를 사용한다.
    ex) alpine 이미지는 매우 작은 크기로 최소한의 기능만 포함한다.

2. 멀티 스테이지 빌드 사용

  • Dockerfile에서 멀티 스테이지 빌드를 사용하여 빌드 단계에만 필요한 도구를 최종 이미지에서 제외시킨다.
    이 방식을 사용하면 최종 이미지에는 애플리케이션 실행에 필요한 파일돠 디펜던시만 포함된다.
  • 멀티 스테이지 빌드는 여러개의 FROM 명령어를 사용하여 구현되며, 각 스테이지는 독립적인 베이스 이미지를 가질 수 있다.
    첫 번째 스테이지에서는 빌드에 필요한 도구와 소스 코드를 컴파일하는 데 필요한 작업을 수행.
    이후 스테이지에서는 첫 번째 스테이지에서 생성된 아티팩트만을 가져와서 최종 이미지를 생성.
    이렇게 하면 불필요한 빌드 도구나 중간 생성물을 최종 이미지에서 제외할 수 있어 이미지 크기가 상당히 줄어듬.

3. 필요 없는 파일 제거

  • 빌드 과정에서 생성되는 임시 파일, 캐시 파일 등 필요 없는 파일은 RUN 명령어에서 && rm -rf /path/to/temporary/files와 같이 제거하여 이미지 크기를 줄인다.

4. 레이어 수 최소화

  • RUN, COPY, ADD 명령어는 새로운 레이어를 생성한다.
    이러한 명령어들을 적절히 조합하여 가능한 한 적은 수의 레이어를 생성하도록 Dockerfile을 최적화한다.

5. COPY와 ADD 명령어를 신중하게 사용

  • COPY와 ADD는 필요한 파일만 이미지에 추가하도록 사용한다.
  • .dockerignore 파일을 사용하여 불필요한 파일이 이미지에 포함되지 않도록 설정할 수 있다.

6. 환경 변수를 이용한 설정

  • 가능한 설정 파일 대신 환경 변수를 사용하여 애플리케이션을 구성한다.
    이 방법은 설정 변경이 필요할 때 이미지를 다시 빌드하지 않아도 되므로 이미지 크기를 줄이는 데 도움이 된다.

7. 적절한 태그 사용

  • 소프트웨어의 적절한 버전을 지정하여 불필요한 업데이트로 인한 크기 증가를 피한다.

 

실제 배포를 위해 컨테이너-호스트 간 파일 복사하기

 

docker container cp

 

docs.docker.com

 

How to copy files from host to Docker container?

I am trying to build a backup and restore solution for the Docker containers that we work with. I have Docker base image that I have created, ubuntu:base, and do not want have to rebuild it each t...

stackoverflow.com

docker cp 명령어는 실행 중인 도커 컨테이너와 호스트 사이에서 파일이나 디렉토리를 복사하는 데 사용된다.
이 명령어는 컨테이너의 파일 시스템과 호스트의 파일 시스템간의 데이터를 쉽게 이동할 수 있게 해줌

docker cp 명령어의 기본 구조

  • 호스트에서 컨테이너로 파일이나 디렉토리 복사하기
    호스트의 myfile.txt를 mycontainer라는 이름의 컨테이너의 /usr/src/app 디렉토리로 복사
    명령어 예시) docker cp myfile.txt mycontainer:/usr/src/app/myfile.txt
    docker cp <호스트의 파일 경로> <컨테이너 이름>:<컨테이너 내 경로>

  • 컨테이너에서 호스트로 파일이나 디렉토리 복사하기
    mycontainer 컨테이너의 /usr/src/app/myfile.txt를 호스트의 현재 작업 디렉토리로 복사
    명령어 예시) docker cp mycontainer:/usr/src/app/myfile.txt ./myfile.txt
    docker cp <컨테이너 이름>:<컨테이너 내 파일 경로> <호스트의 경로>

💡팁!

docker cp 명령어를 사용할 때, 컨테이너 이름 대신 컨테이너 ID를 사용할 수도 있다.

또한, 디렉토리를 복사할 때는 디렉토리내의 모든 파일과 하위 디렉토리가 함께 복사된다.

  • 이 명령어는 로그 파일, 설정 파일, 애플리케이션의 데이터 등 컨테이너 내부나 외부에서 필요한 데이터를 쉽게 이동시키는 데 유용하다. 그러나, 컨테이너의 실행 중인 서비스에 필수적인 파일을 변경하거나 삭제할 때는 주의가 필요!

nginx 파일 복사해서 초기화면 바꿔주기

Nginx 컨테이너의 초기 화면 메시지를 변경하기 위해 호스트에서 컨테이너로 파일을 복사하는 실습 예제

(이 예제에서는 Nginx의 기본 웹 페이지를 호스트에서 준비한 새로운 index.html 파일로 교체)

 

1. Nginx 컨테이너 실행하기

먼저, Nginx 컨테이너를 실행한다. 만약 아직 Nginx 컨테이너가 실행되지 않았다면, 다음 명령어로 Nginx 컨테이너를 시작할 수 있다.

docker run --name my-nginx -p 8080:80 -d nginx

my-nginx라는 이름으로 Nginx 컨테이너를 실행하며, 호스트의 8080 포트를 컨테이너의 80포트에 연결.

2. 새로운 index.html 파일 작성하기

호스트 시스템에서 다음과 같은 index.html을 작성한다.

<!DOCTYPE html>
<html>
<head>
<title>Welcome to My Nginx!</title>
</head>
<body>
<h1>Hello, Docker!</h1>
<p>This is my custom Nginx homepage served from a Docker container.</p>
</body>
</html>

 

3. index.html 파일을 컨테이너로 복사하기

작성한 index.html 파일을 Nginx 컨테이너의 /usr/share/nginx/html 디렉토리로 복사한다.

이 디렉토리는 Nginx에서 기본적으로 정적 파일을 제공하는 위치다.

docker cp index.html my-nginx:/usr/share/nginx/html/index.html

Successfully copied가 뜨면 copy 성공.

4. 변경 사항 확인하기

파일 복사가 완료되면, 브라우저를 통해 http://localhost:8080에 접속하여 변경된 초기 화면 메시지를 확인할 수 있다.

새로운 index.html 파일의 내용이 반영되어 "Hello, Docker!" 메시지가 표시되면 성공.

 

Docker compose 개념

도커 컴포즈(Docker Compose)는 여러 컨테이너를 정의하고 실행하기 위한 도구. YAML 파일을 사용하여 애플리케이션의 서비스, 네트워크, 볼륨 등을 구성하며, 이 파일을 기반으로 한 명령어로 모든 서비스를 빌드하고 시작할 수 있다.

  • 간편한 구성: docker-compose.yml 파일 하나로 전체 애플리케이션 스택의 설정을 관리할 수 있다. YAML파일에는 애플리케이션을 구성하는 모든 컨테이너, 그 컨테이너들이 사용할 이미지, 포트 매핑, 볼륨 마운트, 환경 변수 등이 정의된다.
  • 명령어 단순화: 도커 컴포즈는 docker-compose up, docker-compose down 같은 간단한 명령어를 통해 서비스를 생성, 시작, 중지할 수 있다.
  • 개발 효율성 증대: 개발자는 로컬 환경에서 전체 애플리케이션을 시뮬레이션하고 테스트할 수 있다. 컨테이너화된 환경 덕분에 다른 개발자나 환경과의 충돌 없이 독립적으로 작업할 수 있다.
  • 다중 서비스 관리: 복잡한 애플리케이션을 구성하는 다수의 서비스(DB, 백엔드, 프론트엔드 등)를 한 번에 관리할 수 있다. 각 서비스는 독립적인 컨테이너로 실행되지만, 도커 컴포즈를 통해 서로 연결되고 조율된다.

도커 컴포즈 파일은 여러 도커 컨테이너를 정의하고 실행하기 위한 YAML 형식의 설정 파일이다. 이 파일을 통해 서비스, 네트워크, 볼륨 등을 정의하고 관리할 수 있다.

도커 컴포즈 파일의 기본 구조

1. 버전 (version)

  • 도커 컴포즈 파일의 버전을 명시.
  • 버전에 따라 사용할 수 있는 구성 옵션이 다르며, 일반적으로 최신 버전 사용 권장
     
     
    version: '3'
    

2. 서비스 (services)

  • 애플리케이션을 구성하는 컨테이너들을 정의.
  • 각 서비스는 하나의 컨테이너를 의미.
  • 도커 이미지, 포트 바인딩, 볼륨 마운트 등 컨테이너를 실행하기 위한 설정을 포함. 
  • services: web: image: nginx ports: - "8080:80" db: image: postgres volumes: - db-data:/var/lib/postgresql/data
 
 

3. 네트워크 (networks)

  • 컨테이너 간 통신을 위한 네트워크를 정의.
  • 사용자 정의 네트워크를 생성하여 서비스들이 통신할 수 있는 네트워크 환경을 구성할 수 있다.
    networks:
      app-network:
 
 

4. 볼륨 (volumes)

  • 데이터를 영구적으로 저장하기 위한 볼륨읠 정의.
  • 컨테이너가 삭제되어도 데이터를 보존하며, 여러 컨테이너 간에 데이터를 공유할 수 있도록 한다.
    volumes:
      db-data:
 
 

 

5. 기타 구성 요소

  • 환경 변수(environment), 컨테이너 종속성(depends_on), 컨테이너 구성 옵션(configs), 비밀 키(secrets) 등 추가적인 구성 요소를 정의하여 더욱 복잡한 애플리케이션을 관리할 수 있다.
  • 도커 컴포즈 파일을 사용하면 여러 컨테이너로 구성된 애플리케이션을 한 곳에서 관리할 수 있으며, docker-compose up 명령어 하나로 모든 서비스를 시작하고, docker-compose down 명령어로 중지시킬 수 있다. 이로써 애플리케이션의 배포와 관리 과정이 대폭 간소화된다.
  • 실제 컴포넌트 개발에 적용할 때 참조 : https://github.com/docker/awesome-compose
 

GitHub - docker/awesome-compose: Awesome Docker Compose samples

Awesome Docker Compose samples. Contribute to docker/awesome-compose development by creating an account on GitHub.

github.com

 

Volumes

컴퓨터 과학(CS)에서 볼륨은 데이터 저장 공간을 의미하는 용어로 사용된다.

하드 드라이브, SSD, 네트워크에 연결된 스토리지 시스템에서 데이터를 저장하는 데 사용되는 논리적인 파티션이나 단위를 가리킨다.

파일 시스템을 포함할 수 있으며, 운영 체제는 볼륨을 통해 데이터에 접근하고 관리한다.

 

  • 데이터 조직화: 볼륨을 사용하면 데이터를 더욱 체계적으로 조직화하고 관리할 수 있다.
    사용자 데이터, 애플리케이션 데이터, 백업 등을 서로 다른 볼륨에 저장하여 관리할 수 있다.
  • 보안 및 접근 제어: 볼륨 단위로 보안 정책과 접근 제어를 설정함으로써 데이터 보안을 강화할 수 있다.
  • 백업 및 복구: 볼륨은 백업과 복구 작업을 용이하게 한다. 특정 볼륨만을 대상으로 백업하거나 복구함으로써, 효율적으로 데이터를 보호할 수 있다.
  • 성능 최적화: 데이터를 여러 볼륨에 분산시키면, I/O 작업의 부하를 분산시켜 전체 시스템의 성능을 향상시킬 수 있다.

 

Volume의 의의

 

볼륨은 도커 호스트의 파일 시스템에 위치하며, 하나 이상의 컨테이너에 마운트되어 사용될 수 있다.

컨테이너는 기본적으로 일시적이며 상태가 없기 때문에, 컨테이너 내부에 저장된 데이터는 컨테이너가 삭제될 때 함께 사라진다.

도커에서 스토리지 관리 측면에서 볼륨은 데이터를 영구적으로 저장하고 관리하기 위한 메커니즘을 제공한다. 볼륨을 사용하면 데이터를 컨테이너의 생명주기와 독립적으로 보존할 수 있다.

 

 

Volume의 이점

  • 데이터의 영구성: 볼륨에 저장된 데이터는 컨테이너가 삭제되어도 보존된다. 따라서 중요한 데이터를 안전하게 관리할 수 있다.
  • 데이터 공유 및 재사용: 볼륨은 여러 컨테이너 간에 마운트되어 공유될 수 있어, 다양한 컨테이너에서 동일한 데이터에 접근하거나 데이터를 재사용할 수 있다.
  • 데이터 백업, 복구 및 마이그레이션: 볼륨을 사용하면 데이터를 백업하고 필요할 때 복구하는 것이 용이하다. 또한, 볼륨을 이용해 데이터를 한 호스트에서 다른 호스트로 쉽게 이동할 수 있다.

Volume 관련 주요 도커 명령어

  • docker volume create: 새로운 볼륨을 생성
  • docker volume ls: 생성된 볼륨 목록을 조회
  • docker volume rm: 지정한 볼륨을 삭제
  • docker volume inspect: 지정한 볼륨의 상세 정보를 조회

볼륨을 컨테이너에 마운트하기 위해서는 docker run 명령어 실행 시 -v 또는 --mount 플래그를 사용한다.

예를 들어, myvolume이라는 볼륨을 컨테이너의 /app 디렉토리에 마운트하려면 다음과 같이 실행할 수 있다.

docker run -v myvolume:/app <이미지 이름>

도커 볼륨을 사용함으로써 애플리케이션과 관련된 데이터를 효과적으로 관리하고, 컨테이너 기반의 애플리케이션 개발 및 운영에 있어 중요한 데이터를 안전하게 보호할 수 있다.

스토리지 마운트(도커에서 데이터를 관리하는 방법)에는 두 가지 방법을 사용한다.

1.바인드 마운트

호스트 시스템의 특정 경로를 컨테이너 내부의 경로에 직접 연결하는 방법.

이를 통해 컨테이너가 호스트 시스템의 파일이나 디렉토리에 접근할 수 있다.

 

개발 환경에서 코드나 데이터를 빠르게 반복해서 테스트할 때 유용하다.
파일 시스템의 특정 부분만 컨테이너와 공유하려는 경우에 적합하다.

 

※주의: 바인드 마운트는 호스트 시스템의 파일 시스템 구조에 의존하므로, 이식성이 떨어진다.

 

예시: 호스트의 현재 디렉토리에 있는 index.html 파일을 Nginx 컨테이너의 /usr/share/nginx/html 경로에 배치하는 명령어는 다음과 같다.

  1. 현재 디렉토리에 index.html 파일이 있다고 가정.
  2. 다음 명령어를 사용하여 Nginx 컨테이너를 실행하고, 현재 디렉토리를 컨테이너에 바인드 마운트.
 
docker run --name my-nginx -v $(pwd):/usr/share/nginx/html:ro -p 8080:80 -d nginx

2. 볼륨

도커가 관리하는 데이터의 저장소.

컨테이너와 독립적으로 존재하여 데이터를 보관할 수 있고, 하나 이상의 컨테이너에서 사용할 수 있다.

 

도커가 관리하기 때문에 이식성이 높고, 데이터를 안전하게 보관할 수 있다.
여러 컨테이너 간에 데이터를 공유하거나 데이터의 지속적인 저장이 필요한 경우에 적합하다.

 

※주의: 볼륨은 도커의 관리 하에 있기 때문에, 호스트 시스템의 파일 시스템 경로를 직접 지정할 수 없다.

 

예시: 볼륨을 사용하여 index.html 파일을 Nginx 컨테이너에 배치하는 방법은 다음과 같다.

  1. 볼륨을 생성한다.
    docker volume create my-nginx-volume
    
     
  2. 호스트의 index.html 파일을 볼륨에 복사한다.
    이 작업은 직접적으로 불가능하므로, 임시 컨테이너를 사용해 볼륨에 파일을 복사할 수 있다.
  3. 볼륨을 Nginx 컨테이너에 마운트하여 실행한다.
     
    docker run --name my-nginx -v my-nginx-volume:/usr/share/nginx/html -p 8080:80 -d nginx
    

     

※실제로 호스트의 파일을 볼륨에 복사하는 과정은 더 복잡하며, 일반적으로 초기 컨테이너 설정이나 Dockerfile을 통해 이루어진다. 바인드 마운트의 경우처럼 간단하게 파일을 컨테이너에 넣을 수 없기 때문에, 볼륨을 사용할 때는 파일을 볼륨에 미리 넣거나, 컨테이너 내부에서 파일을 다운로드하는 등의 방법을 사용해야 한다.

 

마무리

오늘은 로컬 환경에서 세팅하는 방법, 파일 복사, docker compose, 볼륨에 대한 아주 기초적인 내용을 배워봤는데 정말 기초적인 거라 그런가 아쉬움이 많이 남는 강의였다...

(도커에 대해 더 자세하게 배우려면 따로 학습이 필요할 거 같다)

 

실제 서버에 배포하는 건 가르쳐주지 않는 거 같아서

따로 서버 배포하는 강의를 봐서 실습을 해봐야할 거 같다.