전체 과정 설명
- 과정 설계 - 이론 + 실습시연 + 실제 면접 질문 + QnA(쉬는 시간 10분 전 + 수업 마지막 시간 30분 전 - QnA시간양은 유동적으로 조정)
- 4회동안 compact 하게 큰 그림을 그려봅시다 - 세부 사항 학습 자습 병행 (mac os / windows)
- 20% 핵심
- 포트폴리오에 어떻게 적용되는지 - 서비스 운영환경에 대한 경험
주요 컨셉 복습
로컬 환경에서 Docker 실행
- 자습 문제 실행
- 공식 블로그 : https://www.docker.com/blog/kickstart-your-spring-boot-application-development/
- github 에서 다운로드 혹은 아래 폴더에서 spring-docker-demo 다운로드
docker build --platform linux/amd64 -t spring-helloworld .
docker run -p 8080:8080 -t spring-helloworld
docker run -d -p 8080:8080 -t spring-helloworld
- log 확인을 터미널/docker desktop 에서 확인해보기
- [실습] 두 명령어의 차이는? 공!식!문!서! 직접 찾아봅시다.
- https://docs.docker.com/ 여기에서부터 시작해서 아래 내용까지 찾아보기 연습!
- https://docs.docker.com/reference/cli/docker/container/run/
- option
-d
: 백그라운드 실행
- https://docs.docker.com/ 여기에서부터 시작해서 아래 내용까지 찾아보기 연습!
- 공식 블로그 : https://www.docker.com/blog/kickstart-your-spring-boot-application-development/
DockerFile 작성하기
Dockerfile
은 도커 이미지를 구축하기 위해 명령어들을 순차적으로 나열한 텍스트 파일이다. 각각의 명령어는 이미지의 새로운 계층을 만들어 내며, 이러한 계층들이 합쳐져 최종적인 이미지를 형성한다.Dockerfile
작성의 기본 구조와 주요 명령어는 다음과 같다:샘플
1 2 3 4 5 6
# 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
2단계: JAR 파일을 실행하기 위한 새로운 레이어
FROM openjdk:11
WORKDIR /app
COPY –from=build /app/target/*.jar app.jar
EXPOSE 8080
CMD [“java”, “-jar”, “app.jar”]
1
2
3
4
5
6
7
8
1. Maven 기반 이미지를 사용하여 소스 코드를 컨테이너 내부로 복사하고, Maven을 사용해 애플리케이션을 빌드
2. OpenJDK 기반 이미지를 사용하여 빌드 단계에서 생성된 JAR 파일을 복사하고, Java 애플리케이션을 실행
### 기본 구조 및 명령어
1. **FROM**: 기반 이미지를 지정한다. 모든 `Dockerfile`은 `FROM` 명령어로 시작해야 하며, 이는 빌드 과정의 기점이 되는 이미지를 정의한다.
```dockerfile
FROM ubuntu:18.04
LABEL: 이미지에 메타데이터를 추가한다. 예를 들어, 이미지의 제작자 정보를 포함할 수 있다.
1
LABEL maintainer="name@example.com"
RUN: 이미지 빌드 과정 중에 명령어를 실행한다. 주로 패키지 설치나 설정 파일 변경에 사용된다.
1
RUN apt-get update && apt-get install -y python
COPY: 호스트의 파일이나 디렉토리를 이미지 내부로 복사한다. 애플리케이션의 소스 코드를 이미지에 추가할 때 주로 사용된다.
1
COPY . /app
ADD:
COPY
명령어와 유사하지만, 원격 URL에서 파일을 추가하거나 로컬의 압축 파일을 압축 해제하며 파일을 추가할 수 있다.1
ADD https://example.com/big.tar.xz /usr/src/things/
CMD: 컨테이너가 시작될 때 실행할 기본 명령어를 정의한다.
Dockerfile
내에서 한 번만 사용할 수 있다.1
CMD ["python", "./app/app.py"]
EXPOSE: 컨테이너가 리스닝할 포트를 지정한다. 네트워킹 구성에 도움을 준다.
1
EXPOSE 80
ENV: 환경 변수를 설정한다. 애플리케이션 설정에 사용된다.
1
ENV API_KEY="YOUR_API_KEY"
WORKDIR:
RUN
,CMD
,ENTRYPOINT
,COPY
,ADD
명령어가 실행될 작업 디렉토리를 설정한다.1
WORKDIR /app
ENTRYPOINT: 컨테이너가 시작될 때 실행할 명령어를 설정한다.
CMD
와 함께 사용되어 애플리케이션의 실행 방식을 정의할 수 있다.1 2
ENTRYPOINT ["python"] CMD ["app.py"]
Dockerfile
을 준비한 후에는docker build
명령어를 통해 이미지를 빌드할 수 있다. 이때Dockerfile
내의 지시어들이 순서대로 실행되어 최종 이미지가 생성된다.Dockerfile
을 활용함으로써 애플리케이션의 빌드와 배포 과정을 표준화하고 자동화할 수 있으며, 이는 개발의 효율성을 높이는 데 기여한다.- LEGO 처럼 조립하는 개념
실제 배포 체크 포인트
도커 이미지 최적화
도커 이미지의 크기를 줄이기 위한 Dockerfile
최적화 전략에는 여러 방법이 있다. 이미지의 효율성을 높이고, 배포 시간을 단축하며, 보안을 강화하는 데 중요하다. 여기 몇 가지 핵심 전략과 멀티 스테이지 빌드에 대한 자세한 설명을 추가해본다:
- 경량 베이스 이미지 사용하기
- 가능한 가장 경량의 베이스 이미지를 사용한다. 예를 들어,
alpine
이미지는 매우 작은 크기로 필요한 최소한의 기능만 포함한다.
- 멀티 스테이지 빌드 사용하기
Dockerfile
에서 멀티 스테이지 빌드를 사용하여 빌드 단계에만 필요한 도구를 최종 이미지에서 제외시킨다. 이 방식을 사용하면 최종 이미지에는 애플리케이션 실행에 필요한 파일과 디펜던시만 포함된다. 멀티 스테이지 빌드는 여러 개의FROM
명령어를 사용하여 구현되며, 각 스테이지는 독립적인 베이스 이미지를 가질 수 있다. 첫 번째 스테이지에서는 빌드에 필요한 도구와 소스 코드를 컴파일하는 데 필요한 작업을 수행한다. 이후 스테이지에서는 첫 번째 스테이지에서 생성된 아티팩트만을 가져와서 최종 이미지를 생성한다. 이렇게 하면 불필요한 빌드 도구나 중간 생성물을 최종 이미지에서 제외할 수 있어 이미지 크기가 상당히 줄어든다.
- 필요 없는 파일 제거하기
- 빌드 과정에서 생성되는 임시 파일, 캐시 파일 등 필요 없는 파일은
RUN
명령어에서&& rm -rf /path/to/temporary/files
와 같이 제거하여 이미지 크기를 줄인다.
- 레이어 수 최소화하기
RUN
,COPY
,ADD
명령어는 새로운 레이어를 생성한다. 이러한 명령어를 적절히 조합하여 가능한 한 적은 수의 레이어를 생성하도록Dockerfile
을 최적화한다.
COPY
와ADD
명령어를 신중하게 사용하기
COPY
와ADD
는 필요한 파일만 이미지에 추가하도록 사용한다..dockerignore
파일을 사용하여 불필요한 파일이 이미지에 포함되지 않도록 설정할 수 있다.
- 환경 변수를 이용한 설정하기
- 가능한 설정 파일 대신 환경 변수를 사용하여 애플리케이션을 구성한다. 이 방법은 설정 변경이 필요할 때 이미지를 다시 빌드하지 않아도 되므로 이미지 크기를 줄이는 데 도움이 된다.
- 적절한 태그 사용하기
- 필요한 소프트웨어의 적절한 버전을 지정하여 불필요한 업데이트로 인한 크기 증가를 피한다.
이러한 전략들을 적용함으로써 도커 이미지의 크기를 효과적으로 줄이고, 배포 및 실행 시간을 단축시키며, 보안을 강화할 수 있다.
실제 배포를 위해 컨테이너-호스트 간 파일 복사하기
- https://docs.docker.com/reference/cli/docker/container/cp/
docker cp
명령어는 실행 중인 도커 컨테이너와 호스트 사이에서 파일이나 디렉토리를 복사하는 데 사용된다. 이 명령어는 컨테이너의 파일 시스템과 호스트의 파일 시스템 간의 데이터를 쉽게 이동할 수 있게 해준다.
docker cp
명령어의 기본 구조는 다음과 같다:
호스트에서 컨테이너로 파일이나 디렉토리 복사하기:
1
docker cp <호스트의 파일 경로> <컨테이너 이름>:<컨테이너 내 경로>
예를 들어, 호스트의
myfile.txt
를mycontainer
라는 이름의 컨테이너의/usr/src/app
디렉토리로 복사하고 싶다면, 다음과 같이 실행한다:1
docker cp myfile.txt mycontainer:/usr/src/app/myfile.txt
컨테이너에서 호스트로 파일이나 디렉토리 복사하기:
1
docker cp <컨테이너 이름>:<컨테이너 내 파일 경로> <호스트의 경로>
예를 들어,
mycontainer
컨테이너의/usr/src/app/myfile.txt
를 호스트의 현재 작업 디렉토리로 복사하고 싶다면, 다음과 같이 실행한다:1
docker cp mycontainer:/usr/src/app/myfile.txt ./myfile.txt
docker cp
명령어를 사용할 때, 컨테이너 이름 대신 컨테이너 ID를 사용할 수도 있다. 또한, 디렉토리를 복사할 때는 디렉토리 내의 모든 파일과 하위 디렉토리가 함께 복사된다.
- 이 명령어는 로그 파일, 설정 파일, 애플리케이션의 데이터 등 컨테이너 내부나 외부에서 필요한 데이터를 쉽게 이동시키는 데 유용하다. 그러나, 컨테이너의 실행 중인 서비스에 필수적인 파일을 변경하거나 삭제할 때는 주의가 필요하다.
- [실습] nginx 파일 복사해서 초기화면 바꿔주기
- Nginx 컨테이너의 초기 화면 메시지를 변경하기 위해 호스트에서 컨테이너로 파일을 복사하는 실습 예제를 다음과 같이 진행할 수 있다. 이 예제에서는 Nginx의 기본 웹 페이지를 호스트에서 준비한 새로운
index.html
파일로 교체한다.
- Nginx 컨테이너의 초기 화면 메시지를 변경하기 위해 호스트에서 컨테이너로 파일을 복사하는 실습 예제를 다음과 같이 진행할 수 있다. 이 예제에서는 Nginx의 기본 웹 페이지를 호스트에서 준비한 새로운
- Nginx 컨테이너 실행하기
먼저, Nginx 컨테이너를 실행한다. 만약 아직 Nginx 컨테이너가 실행되지 않았다면, 다음 명령어로 Nginx 컨테이너를 시작할 수 있다.
1
docker run --name my-nginx -p 8080:80 -d nginx
이 명령어는 my-nginx
라는 이름으로 Nginx 컨테이너를 실행하며, 호스트의 8080 포트를 컨테이너의 80 포트에 연결한다.
- 새로운
index.html
파일 작성하기
호스트 시스템에서 새로운 index.html
파일을 작성한다. 예를 들어, 다음과 같은 내용을 담은 index.html
파일을 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
<!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>
index.html
파일을 컨테이너로 복사하기
작성한 index.html
파일을 Nginx 컨테이너의 /usr/share/nginx/html
디렉토리로 복사한다. 이 디렉토리는 Nginx에서 기본적으로 정적 파일을 제공하는 위치다.
1
docker cp index.html my-nginx:/usr/share/nginx/html/index.html
- 변경 사항 확인하기
파일 복사가 완료되면, 브라우저를 통해 http://localhost:8080
에 접속하여 변경된 초기 화면 메시지를 확인할 수 있다. 새로운 index.html
파일의 내용이 반영되어 “Hello, Docker!” 메시지가 표시되어야 한다.
Docker compose 개념
도커 컴포즈(Docker Compose)는 여러 컨테이너를 정의하고 실행하기 위한 도구다. YAML 파일을 사용하여 애플리케이션의 서비스, 네트워크, 볼륨 등을 구성하며, 이 파일을 기반으로 한 명령어로 모든 서비스를 빌드하고 시작할 수 있다. 도커 컴포즈는 복잡한 멀티 컨테이너 애플리케이션을 쉽게 관리하고, 개발, 테스팅, 스테이징, 프로덕션 환경에서의 일관성을 보장하는 데 유용하다.
도커 컴포즈의 주요 특징은 다음과 같다:
간편한 구성:
docker-compose.yml
파일 하나로 전체 애플리케이션 스택의 설정을 관리할 수 있다. 이 YAML 파일에는 애플리케이션을 구성하는 모든 컨테이너, 그 컨테이너들이 사용할 이미지, 포트 매핑, 볼륨 마운트, 환경 변수 등이 정의된다.명령어 단순화: 도커 컴포즈는
docker-compose up
,docker-compose down
같은 간단한 명령어를 통해 서비스를 생성, 시작, 중지할 수 있다. 이는 개발 과정을 효율적으로 만들어 준다.개발 효율성 증대: 개발자는 로컬 환경에서 전체 애플리케이션을 손쉽게 시뮬레이션하고 테스트할 수 있다. 컨테이너화된 환경 덕분에 다른 개발자나 환경과의 충돌 없이 독립적으로 작업할 수 있다.
환경 일관성 보장: 도커 컴포즈를 사용하면 개발부터 프로덕션까지 애플리케이션의 환경을 일관되게 유지할 수 있다. 이는 “개발 환경에서는 잘 동작했는데, 실제 환경에서는 안 된다”는 문제를 방지해 준다.
다중 서비스 관리: 복잡한 애플리케이션을 구성하는 다수의 서비스(예: 데이터베이스, 백엔드, 프론트엔드 등)를 한 번에 관리할 수 있다. 각 서비스는 독립적인 컨테이너로 실행되지만, 도커 컴포즈를 통해 서로 연결되고 조율된다.
도커 컴포즈는 개발 초기 단계에서부터 애플리케이션의 배포까지 전 과정에서 개발자의 작업을 단순화하고 가속화하는 효율적인 도구다.
[실습] 공식문서를 제대로 활용하자! -> 한땀한땀 같이 읽어보면서 공식문서 활용방법 익혀보기
도커 컴포즈 파일은 여러 도커 컨테이너를 정의하고 실행하기 위한 YAML 형식의 설정 파일이다. 이 파일을 통해 서비스, 네트워크, 볼륨 등을 정의하고 관리할 수 있다. 도커 컴포즈 파일의 기본 구조는 다음과 같이 구성된다:
- 버전 (version)
도커 컴포즈 파일의 버전을 명시한다. 버전에 따라 사용할 수 있는 구성 옵션이 다르며, 일반적으로 최신 버전을 사용하는 것이 좋다.
1
version: '3'
- 서비스 (services)
애플리케이션을 구성하는 컨테이너들을 정의한다. 각 서비스는 하나의 컨테이너를 의미하며, 도커 이미지, 포트 바인딩, 볼륨 마운트 등 컨테이너를 실행하기 위한 설정을 포함한다.
1 2 3 4 5 6 7 8 9
services: web: image: nginx ports: - "8080:80" db: image: postgres volumes: - db-data:/var/lib/postgresql/data
- 네트워크 (networks)
컨테이너 간 통신을 위한 네트워크를 정의한다. 사용자 정의 네트워크를 생성하여 서비스들이 통신할 수 있는 네트워크 환경을 구성할 수 있다.
1 2
networks: app-network:
- 볼륨 (volumes)
데이터를 영구적으로 저장하기 위한 볼륨을 정의한다. 볼륨은 컨테이너가 삭제되어도 데이터를 보존하며, 여러 컨테이너 간에 데이터를 공유할 수 있도록 한다.
1 2
volumes: db-data:
- 기타 구성 요소
환경 변수 (environment), 컨테이너 종속성 (depends_on), 컨테이너 구성 옵션 (configs), 비밀 키 (secrets) 등 추가적인 구성 요소를 정의하여 더욱 복잡한 애플리케이션을 관리할 수 있다.
도커 컴포즈 파일을 사용하면 여러 컨테이너로 구성된 애플리케이션을 한 곳에서 관리할 수 있으며,
docker-compose up
명령어 하나로 모든 서비스를 시작하고,docker-compose down
명령어로 중지시킬 수 있다. 이로써 애플리케이션의 배포와 관리 과정이 대폭 간소화된다.[꿀팁] 실제 컴포넌트 개발에 적용할 때도 여기서부터! https://github.com/docker/awesome-compose
Volumes
container 는 불변하지 않는다. 한번 사용되는 개념. 인스턴스와 유사.
- Kumar, Rajesh. “Docker Tutorials: Lifecycle of Docker Containers - DevOpsSchool.com.” DevOpsSchool.com, 3 Oct. 2022, www.devopsschool.com/blog/lifecycle-of-docker-containers/.
그러면 persistence 해야하는 데이터들은 어떻게 해야하나?
[용어] volume
컴퓨터 과학(CS)에서 볼륨은 데이터 저장 공간을 의미하는 용어로 사용된다. 일반적으로, 볼륨은 하드 드라이브, SSD, 또는 네트워크에 연결된 스토리지 시스템에서 데이터를 저장하는 데 사용되는 논리적인 파티션이나 단위를 가리킨다. 볼륨은 파일 시스템을 포함할 수 있으며, 운영 체제는 볼륨을 통해 데이터에 접근하고 관리한다.
볼륨은 물리적인 스토리지 디바이스를 논리적으로 구분하여 관리할 수 있게 해주며, 다음과 같은 목적으로 사용될 수 있다:
- 데이터 조직화: 볼륨을 사용하면 데이터를 더욱 체계적으로 조직화하고 관리할 수 있다. 예를 들어, 사용자 데이터, 애플리케이션 데이터, 백업 등을 서로 다른 볼륨에 저장하여 관리할 수 있다.
- 보안 및 접근 제어: 볼륨 단위로 보안 정책과 접근 제어를 설정함으로써 데이터 보안을 강화할 수 있다.
- 백업 및 복구: 볼륨은 백업과 복구 작업을 용이하게 한다. 특정 볼륨만을 대상으로 백업하거나 복구함으로써, 효율적으로 데이터를 보호할 수 있다.
- 성능 최적화: 데이터를 여러 볼륨에 분산시키면, I/O 작업의 부하를 분산시켜 전체 시스템의 성능을 향상시킬 수 있다.
볼륨 관리는 운영 체제나 스토리지 관리 소프트웨어를 통해 이루어진다. 현대의 운영 체제는 볼륨을 생성하고, 포맷하며, 마운트하는 기능을 제공한다. 클라우드 컴퓨팅 환경에서는 볼륨을 가상화하여, 필요에 따라 동적으로 스토리지 용량을 확장하거나 축소할 수 있는 기능도 제공한다.
데이터베이스 시스템, 웹 서버, 파일 서버 등 다양한 애플리케이션과 시스템에서 볼륨은 중요한 데이터 관리 도구로 활용된다. 볼륨을 효과적으로 사용함으로써, 데이터의 안정성, 접근성, 그리고 시스템의 전반적인 성능을 향상시킬 수 있다.
도커에서 스토리지 관리 측면에서 볼륨은 데이터를 영구적으로 저장하고 관리하기 위한 메커니즘을 제공한다. 컨테이너는 기본적으로 일시적이며 상태가 없기 때문에, 컨테이너 내부에 저장된 데이터는 컨테이너가 삭제될 때 함께 사라진다. 볼륨을 사용하면 이러한 문제를 해결할 수 있으며, 데이터를 컨테이너의 생명주기와 독립적으로 보존할 수 있다.
볼륨은 도커 호스트의 파일 시스템에 위치하며, 하나 이상의 컨테이너에 마운트되어 사용될 수 있다. 볼륨을 사용하면 다음과 같은 이점을 얻을 수 있다:
- 데이터의 영구성: 볼륨에 저장된 데이터는 컨테이너가 삭제되어도 보존된다. 따라서 중요한 데이터를 안전하게 관리할 수 있다.
- 데이터 공유 및 재사용: 볼륨은 여러 컨테이너 간에 마운트되어 공유될 수 있어, 다양한 컨테이너에서 동일한 데이터에 접근하거나 데이터를 재사용할 수 있다.
- 데이터 백업, 복구 및 마이그레이션: 볼륨을 사용하면 데이터를 백업하고 필요할 때 복구하는 것이 용이하다. 또한, 볼륨을 이용해 데이터를 한 호스트에서 다른 호스트로 쉽게 이동할 수 있다.
볼륨을 생성하고 관리하기 위한 주요 도커 명령어는 다음과 같다:
docker volume create
: 새로운 볼륨을 생성한다.docker volume ls
: 생성된 볼륨 목록을 조회한다.docker volume rm
: 지정한 볼륨을 삭제한다.docker volume inspect
: 지정한 볼륨의 상세 정보를 조회한다.
볼륨을 컨테이너에 마운트하기 위해서는 docker run
명령어 실행 시 -v
또는 --mount
플래그를 사용한다. 예를 들어, myvolume
이라는 이름의 볼륨을 컨테이너의 /app
디렉토리에 마운트하려면 다음과 같이 실행할 수 있다:
1
docker run -v myvolume:/app <이미지 이름>
도커 볼륨을 사용함으로써 애플리케이션과 관련된 데이터를 효과적으로 관리하고, 컨테이너 기반의 애플리케이션 개발 및 운영에 있어 중요한 데이터를 안전하게 보호할 수 있다.
- 스토리지 마운트에는 두 가지 방법을 크게 사용함. 바인드 마운트, 볼륨 마운트
- 도커에서 데이터를 관리하는 두 가지 주요 방법은 바인드 마운트와 볼륨이다. 각각의 특성과 사용 예시를 Nginx에서
index.html
파일을 배치하는 경우를 통해 설명한다
- 도커에서 데이터를 관리하는 두 가지 주요 방법은 바인드 마운트와 볼륨이다. 각각의 특성과 사용 예시를 Nginx에서
바인드 마운트 (Bind Mount)
- [실습] https://docs.docker.com/guides/walkthroughs/persist-data/
- 정의: 바인드 마운트는 호스트 시스템의 특정 경로를 컨테이너 내부의 경로에 직접 연결하는 방법이다. 이를 통해 컨테이너가 호스트 시스템의 파일이나 디렉토리에 접근할 수 있다.
- 특징: 개발 환경에서 코드나 데이터를 빠르게 반복해서 테스트할 때 유용하다. 파일 시스템의 특정 부분만 컨테이너와 공유하려는 경우에 적합하다.
- 주의점: 바인드 마운트는 호스트 시스템의 파일 시스템 구조에 의존하므로, 이식성이 떨어진다.
예시: 호스트의 현재 디렉토리에 있는 index.html
파일을 Nginx 컨테이너의 /usr/share/nginx/html
경로에 배치하는 예시는 다음과 같다.
- 현재 디렉토리에
index.html
파일이 있다고 가정한다. - 다음 명령어를 사용하여 Nginx 컨테이너를 실행하고, 현재 디렉토리를 컨테이너에 바인드 마운트한다.
1
docker run --name my-nginx -v $(pwd):/usr/share/nginx/html:ro -p 8080:80 -d nginx
볼륨 (Volume)
- 정의: 볼륨은 도커가 관리하는 데이터의 저장소이다. 컨테이너와 독립적으로 존재하여 데이터를 보관할 수 있고, 하나 이상의 컨테이너에서 사용할 수 있다.
- 특징: 볼륨은 도커가 관리하기 때문에 이식성이 높고, 데이터를 안전하게 보관할 수 있다. 여러 컨테이너 간에 데이터를 공유하거나 데이터의 지속적인 저장이 필요한 경우에 적합하다.
- 주의점: 볼륨은 도커의 관리 하에 있기 때문에, 호스트 시스템의 파일 시스템 경로를 직접 지정할 수 없다.
예시: 볼륨을 사용하여 index.html
파일을 Nginx 컨테이너에 배치하는 방법은 다음과 같다.
- 먼저 볼륨을 생성한다.
1
docker volume create my-nginx-volume
호스트의
index.html
파일을 볼륨에 복사한다. 이 작업은 직접적으로 가능하지 않으므로, 임시 컨테이너를 사용해 볼륨에 파일을 복사할 수 있다.볼륨을 Nginx 컨테이너에 마운트하여 실행한다.
1
docker run --name my-nginx -v my-nginx-volume:/usr/share/nginx/html -p 8080:80 -d nginx
실제로 호스트의 파일을 볼륨에 복사하는 과정은 조금 더 복잡하며, 일반적으로 초기 컨테이너 설정이나 Dockerfile을 통해 이루어진다. 바인드 마운트의 경우처럼 간단하게 파일을 컨테이너에 넣을 수 없기 때문에, 볼륨을 사용할 때는 파일을 볼륨에 미리 넣거나, 컨테이너 내부에서 파일을 다운로드하는 등의 방법을 사용해야 한다.
docker 이미지 같이 사용하기
- Docker hub pull & push 에서 이미지 가져오기/업로드하기
- 공!식!문!서! 에 있을까?
docker login
- Docker Hub에서 Nginx 이미지를 끌어오고, 새로운 태그를 붙여 자신의 Docker Hub 저장소에 올리는 과정은 다음과 같다. 이 과정을 진행하기 전에 Docker Hub 계정이 있어야 하며, 도커가 설치되어 있고 로컬 시스템에서 작동하는 것을 가정한다.
- Nginx 이미지 끌어오기
먼저, Docker Hub에서 Nginx 이미지를 로컬 시스템으로 끌어온다.
1
docker pull nginx
- 이미지에 새로운 태그 붙이기
끌어온 Nginx 이미지에 새로운 태그를 붙인다. 여기서 <your-docker-hub-username>
는 Docker Hub 사용자 이름이며, <tag>
는 원하는 태그명이다.
1
docker tag nginx:latest <your-docker-hub-username>/nginx:<tag>
예를 들어, 사용자 이름이 john
이고, 태그명을 v1
로 하고자 한다면 다음과 같이 입력한다.
1
docker tag nginx:latest john/nginx:v1
- Docker Hub에 로그인하기
이제 자신의 Docker Hub 저장소에 이미지를 올리기 전에 Docker Hub에 로그인해야 한다.
1
docker login
명령어를 실행하면 사용자 이름과 비밀번호를 입력하라는 메시지가 나타난다. Docker Hub 계정의 사용자 이름과 비밀번호를 입력한다.
- 이미지 올리기
로그인한 후, 새로운 태그를 붙인 이미지를 자신의 Docker Hub 저장소에 올릴 수 있다.
1
docker push <your-docker-hub-username>/nginx:<tag>
앞서 예를 든 경우에는 다음과 같이 입력한다.
1
docker push john/nginx:v1
이제, 지정한 태그로 붙인 이미지가 자신의 Docker Hub 저장소에 올라갔다. Docker Hub 웹사이트에 접속하여, 자신의 저장소에서 새로운 이미지를 확인할 수 있다.
이 과정을 통해 Docker Hub에 있는 기존의 이미지를 자신의 계정으로 끌어오고, 새로운 태그를 붙여서 관리할 수 있게 되었다.
Network
- 네트워크란? 노드와 노드간의 커뮤니케이션
- ![images?q=tbn:ANd9GcTw3v868W34nIhEGPv8YDbaqVZGMKwG15iTkmsiHGEPg&s](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTw3v868W34_nIhEGPv8YDbaqVZGMKwG15iTkmsiHGEPg&s)
“What Is a Network Diagram.” _Lucidchart, 2024, www.lucidchart.com/pages/network-diagram.
- ![images?q=tbn:ANd9GcTw3v868W34nIhEGPv8YDbaqVZGMKwG15iTkmsiHGEPg&s](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTw3v868W34_nIhEGPv8YDbaqVZGMKwG15iTkmsiHGEPg&s)
- 컨테이너와 컨테이너 따로 따로 만들면 그냥 연결이 될까? 아니요!
- ->가상 네트워크를 만들고 이 네트워크에 컨테이너를 소속시켜 컨테이너들을 연결한다.
- [실습] 레드마인 + mysql 연결시키기
- 레드마인(Redmine)과 MySQL을 Docker를 사용하여 연결하는 과정은 아래와 같이 사용자 정의 네트워크를 생성하고, MySQL 데이터베이스 컨테이너를 실행하며, 레드마인 컨테이너를 실행하는 세 단계로 구성된다.
- 사용자 정의 네트워크 생성
먼저, 레드마인과 MySQL 컨테이너 간의 통신을 위해 사용자 정의 도커 네트워크를 생성한다.
1
docker network create redmine-network
- MySQL 컨테이너 실행
다음으로, 사용자 정의 네트워크에 MySQL 컨테이너를 실행한다. 레드마인은 데이터를 저장하기 위해 MySQL 데이터베이스를 사용하므로, 먼저 데이터베이스를 준비해야 한다.
1
docker run --name some-mysql --network redmine-network -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_DATABASE=redmine -d mysql:8
이 명령어는 MySQL 8 이미지를 사용하여 some-mysql
이라는 이름의 컨테이너를 생성하고, 사용자 정의 네트워크 redmine-network
에 연결한다. 또한, MySQL 데이터베이스의 루트 비밀번호(MYSQL_ROOT_PASSWORD
)와 레드마인이 사용할 데이터베이스 이름(MYSQL_DATABASE
)을 설정한다.
- 레드마인 컨테이너 실행
마지막으로, MySQL 데이터베이스에 연결된 레드마인 컨테이너를 실행한다. 레드마인 컨테이너 역시 사용자 정의 네트워크에 연결해야 한다.
1
docker run --name some-redmine --network redmine-network -e REDMINE_DB_MYSQL=some-mysql -e REDMINE_DB_PASSWORD=my-secret-pw -p 3000:3000 -d redmine
이 명령어는 redmine
이미지를 사용하여 some-redmine
이라는 이름의 컨테이너를 실행하고, redmine-network
네트워크에 연결한다. MySQL 데이터베이스에 접근하기 위한 정보(REDMINE_DB_MYSQL
, REDMINE_DB_PASSWORD
)를 환경 변수로 설정한다. 마지막으로, 호스트의 3000 포트를 컨테이너의 3000 포트에 매핑하여 외부에서 레드마인에 접근할 수 있도록 한다.
이제 브라우저를 통해 http://localhost:3000
에 접속하면 레드마인의 홈페이지에 접근할 수 있다. 레드마인과 MySQL 컨테이너가 성공적으로 연결되어 있으며, 데이터베이스 설정이 올바르게 구성되어 있다면, 레드마인을 사용하여 프로젝트 관리 작업을 시작할 수 있다.
Docker network 의 종류
- 브릿지 네트워크 먼저 핵심 포인트! 나머지는 Devops 의 영역!
- 도커 네트워크는 컨테이너 간의 통신과 외부 네트워크와의 연결을 관리하는 도커의 기능이다. 이를 통해 개발자는 컨테이너가 서로 어떻게 통신할 수 있는지, 어떤 정책으로 네트워크를 격리할 것인지를 정의할 수 있다. 도커 네트워크는 여러 네트워크 드라이버를 지원하며, 각각의 사용 사례에 따라 적합한 네트워크 환경을 구성할 수 있다.
1. 브리지 네트워크 (Bridge Network)
- 정의: 기본적으로, 각 도커 설치에는 하나의 브리지 네트워크가 존재하며, 컨테이너를 실행할 때 이 네트워크에 자동으로 연결된다. 사용자는 여러 개의 사용자 정의 브리지 네트워크를 생성하여 컨테이너를 논리적으로 분리할 수 있다.
- 사용 사례: 같은 브리지 네트워크에 속한 컨테이너끼리는 서로 통신할 수 있지만, 다른 브리지 네트워크에 속한 컨테이너와는 통신할 수 없다. 이를 통해 애플리케이션의 컴포넌트를 격리할 수 있다.
- ![0cMUND9w1bO1o5sPe.png](https://miro.medium.com/v2/resize:fit:1060/0cMUND9w1bO1o5sPe.png)
- https://medium.com/@xiaopeng163/docker-bridge-networking-deep-dive-3e2e0549e8a0
브릿지 네트워크는 도커 컨테이너들이 동일한 호스트 내에서 서로 통신할 수 있도록 하는 기본 네트워크 타입 중 하나다. 이 네트워크는 가상의 브릿지(bridge)를 통해 각 컨테이너를 연결하며, 이를 통해 컨테이너 간에 데이터를 주고받을 수 있다. 브릿지 네트워크는 컨테이너가 생성될 때 자동으로 생성되는 기본 네트워크(bridge
)와 사용자가 직접 생성할 수 있는 사용자 정의 브릿지 네트워크로 구분할 수 있다.
기본 브릿지 네트워크
- 도커를 설치하면 기본적으로
bridge
라는 이름의 브릿지 네트워크가 생성된다. - 기본 브릿지 네트워크에 연결된 컨테이너는 호스트의 네트워크와는 격리되어 있지만, 같은 네트워크 내의 다른 컨테이너와는 통신할 수 있다.
- 기본 브릿지 네트워크를 사용하는 컨테이너는
-p
또는--publish
옵션을 사용하여 호스트와 특정 포트를 연결하지 않는 이상 외부 네트워크와 직접 통신할 수 없다.
사용자 정의 브릿지 네트워크
- 사용자는
docker network create
명령어를 사용하여 추가 브릿지 네트워크를 생성할 수 있다. - 사용자 정의 브릿지 네트워크는 기본 브릿지 네트워크보다 여러 가지 장점이 있다. 예를 들어, 자동 DNS 해석 기능을 통해 컨테이너 이름을 사용하여 서로 통신할 수 있게 된다.
- 사용자 정의 브릿지 네트워크에 연결된 컨테이너는 보다 높은 수준의 네트워크 격리와 보안을 제공받을 수 있다.
브릿지 네트워크의 장점
- 컨테이너 간 통신: 브릿지 네트워크를 사용하면, 같은 호스트 내의 컨테이너들이 서로 통신할 수 있다.
- 네트워크 격리: 서로 다른 브릿지 네트워크에 속한 컨테이너들은 기본적으로 서로 통신할 수 없으며, 이를 통해 네트워크 격리를 구현할 수 있다.
- DNS 해석: 사용자 정의 브릿지 네트워크는 컨테이너 이름을 DNS 이름으로 사용할 수 있게 해주어, IP 주소 대신 컨테이너 이름으로 통신할 수 있다.
브릿지 네트워크는 도커에서 가장 기본적이면서도 중요한 네트워크 타입 중 하나로, 컨테이너화된 애플리케이션의 통신 구조를 효과적으로 구성할 수 있게 해준다.
2. 호스트 네트워크 (Host Network)
- 정의: 호스트 네트워크를 사용하면 컨테이너가 호스트의 네트워크 스택을 직접 사용할 수 있다. 이 방식을 사용하면 컨테이너는 네트워크 격리 없이 호스트와 동일한 네트워크 환경을 공유한다.
- 사용 사례: 네트워크 격리보다 네트워크 성능을 우선시하는 경우에 적합하다. 예를 들어, 최대한의 네트워크 성능이 요구되는 고성능 웹 서버에 사용할 수 있다.
3. 오버레이 네트워크 (Overlay Network)
- 정의: 오버레이 네트워크는 여러 도커 호스트에 걸쳐 있는 컨테이너 간의 통신을 가능하게 한다. 이 네트워크는 스웜 모드에서 클러스터링된 도커 환경을 위해 설계되었다.
- 사용 사례: 다중 호스트 컨테이너 오케스트레이션을 필요로 하는 대규모 애플리케이션에 적합하다. 오버레이 네트워크는 컨테이너 간의 안전한 통신을 위해 내부적으로 암호화를 지원한다.
4. 맥바이란 네트워크 (Macvlan Network)
- 정의: 맥바이란 네트워크는 컨테이너에 별도의 MAC 주소를 할당하여, 물리 네트워크에 직접 연결된 것처럼 만든다. 이를 통해 컨테이너가 네트워크 상에서 물리적인 장치처럼 동작할 수 있다.
- 사용 사례: 기존의 VLAN에 컨테이너를 통합해야 하는 경우나, 컨테이너가 물리 네트워크 상의 다른 장치들과 통신해야 하는 경우에 사용한다.
도커 네트워크를 사용함으로써, 컨테이너화된 애플리케이션의 네트워킹 요구사항을 유연하게 충족시킬 수 있으며, 애플리케이션의 구성 요소 간에 효과적으로 통신 구조를 설정할 수 있다.
면접 질문
레지스트리에 이미지 공개하실 때 보안적으로 신경쓴 부분이 있으신가요?
도커 컴포즈에서 비밀번호나 API 키와 같은 민감한 정보를 안전하게 관리하는 방법에는 어떤 것들이 있나요?
도커 이미지 크기가 어느정도 되었나요? 어떤 식으로 최적화 하려고 했나요?
Reference.
- Dockerfile Reference https://docs.docker.com/reference/dockerfile/
- 지마켓 공식 블로그 - springboot 와 frontend docker 로 배포하기 https://dev.gmarket.com/80
- awesome compose https://github.com/docker/awesome-compose
레지스트리에 이미지 공개하실 때 보안적으로 신경쓴 부분이 있으신가요?
- dockerfile 안에서 비밀키로 관리해야 하는 환경 변수들은 따로 env 파일로 분리하여 공개하지 않고 ignore 하는 방식으로 보호했다.
도커 이미지 크기가 어느정도 되었나요? 어떤 식으로 최적화 하려고 했나요?
- multi stage build를 통해 최종 실행에 필요한 파일만 남겨 이미지의 크기를 줄일 수 있습니다.
- 도커 허브에서 제공되는 MiniO 이미지가 없어 기본 베이스 이미지로 Ubuntu를 활용하였으나 베이스 이미지 용량이 1GB에 육박하여 리파인 이미지를 활용하여 최적화했었습니다.
- 어플리케이션에 필요한 종속환경을 마련한 후, 멀티 스테이지 빌드를 통해 필요한 환경만을 최소 이미지에 담았습니다. 지속적으로 이미지가 빌드돼야 하는 했기에 소스코드를 copy하는 부분을 밑단 레이어에 배치함으로써 캐시를 적극 활용하였습니다.
도커 이미지 버전별 구분은 어떤 기준으로 하셨나요?
- 실제 서비스 환경을 상정했기 때문에 도커 이미지 구성이 사용자에게 제공되는 안정된 버전이어야 한다고 생각했다. 그래서 한번 수정하고자 계획한 사안을 적용하고 테스트해서 안정성이 확보됐다고 느꼈을 때 새로운 버전명을 붙여서 관리했다.
- 하나의 “실행(사용) 가능한 단위”로 완성된 버전이 되었다면 버전을 새로 붙일 것 같습니다!
- github action을 이용해서 도커 이미지 업로드했는데, 이 때 action이 실행된 commit의 hash를 이용하여 이미지 태그를 설정했습니다.
- 경로가 변경되거나 빌드 도구, 명령어 등이 변경되어 직접적인 동작 수정이 일어나 배포 과정이 달라졌을 때 변경했습니다.
docker 컨테이너를 나누는 기준은 무엇으로 잡으셨나요? 개발환경을 컨테이너 어디까지 나누셨나요?
- 한 컨테이너에 디비와 어플리케이션을 같이 구동하게 될 경우 영속해야 하는 디비가 어플리케이션의 변경에 따라 같이 실행돼야 하므로 비효율적이라고 생각합니다. 변경이 일어난 단위에만 새로운 컨테이너가 실행되는 것이 훨씬 효율적인 방식이라고 생각합니다.
- 개별적으로 실행되는 네트워크 단위를 기준으로 분리하였습니다. DB, CI/CD, 프론트엔드, 백엔드의 각 서비스 등의 단위로 분리했습니다.