Search

Docker Basic

1. 기본

가. About Docker

도커 정의: 오픈소스로 제공되는 컨테이너 기반의 가상화 플랫폼입니다.
도커 사용 이유: 응용프로그램을 보다 쉽게 배포하고 실행하기 때문입니다. 사용자의 로컬 실행환경에 의존하지 않고 프로그램을 실행할 수 있기 때문에 활용성이 높습니다.
컨테이너 정의: 응용프로그램을 편리하고 쉽게 배포 및 관리하기 위해 제공하는 가상 실행환경 또는 인터페이스입니다. 용프로그램이 기존 환경에서 다른 환경으로 옮겨져도 안정적이고 빠르게 실행되는 소프트웨어의 표준 단위로도 이해할 수 있습니다.
컨테이너 이미지 정의: 응용프로그램을 실행하는데 필요한 모든 것(런타임 환경, 시스템 도구, 시스템 라이브러리 및 기본 설정)을 포함하는 소프트웨어 패키지입니다.
컨테이너와 컨테이너 이미지의 관계
: 컨테이너는 이미지의 인스턴스로 가상 실행환경입니다.
: 컨테이너 이미지는 각종 설정 및 종속성을 갖고 있고, 이미지로부터 컨테이너를 생성합니다.
도커 사용의 일반적 흐름
명령어 입력(Docker Client) → 명령 관련 이미지 탐색(local 내 이미지 보관장소) → 이미지 존재여부 확인
? 도커 서버(또는 도커 데몬) 이미지 실행
: 도커 허브에서 도커 서버 내 local Cashe로 가져와서(pulling) 이미지 실행 → 동 명령어 입력 시 local cashe에서 실행
이미지로 컨테이너 만들기
: 이미지 안에 컨테이너 생성 명령어(docker run <이미지>)와 파일 스냅샷(특정 앱 설치에 필요한 파일)이 있습니다.
: 컨테이너 생성 명령어 입력시 컨테이너 내부 HD 리소스에 파일 스냅샷이 할당됩니다. 앱(또는 프로세스)이 커널을 통해 할당된 리소스를 바탕으로 실행됩니다.

나. 도커와 기존 가상화 기술의 차이

공통점: 기본 하드웨어에서 여러 격리된 소프트웨어 환경을 만들고 그 안에 앱을 배치함
차이점: 격리된 환경의 구현 방법
: 기존 가상화 기술(VM 사용)은 각 격리된 환경에 따라 VM 실행하고 그 안에 컴퓨팅 자원 할당 및 Guest OS 부팅 필요. 앱 실행 간 하이퍼바이저가 중간관리합니다. 참고로 하이퍼바이저란 호스트 OS위에서 다수의 게스트 OS를 구동하는 소프트웨어로, 하드웨어 리소스를 가상화하여 각 호스트 OS에 할당하고 VM을 모니터링합니다.
: 도커는 Guest OS 및 하이퍼바이저 불필요합니다. Host OS 위에 Docker Engine을 통해 도커 이미지를 배포하여 각 컨테이너 안에서 앱 실행
도커의 장점은 오버헤드가 적다는 것입니다. 기존 가상화 기술의 경우, Guest OS를 각각 두기 때문에 시스템이 무거워지므로 속도는 느린반면 도커의 경우 Host OS 하나만 두기 때문에 상대적으로 오버헤드가 적다

다. 컨테이너 간 격리 기술

CGroup(Control Groups): 프로세스 그룹의 시스템 리소스 사용량 관리합니다. 특정 앱이 시스템 리소스를 지나치게 많이 사용하면 CGroup으로 분리시켜서 리소스 사용량 제한할 수 있습니다. 앞에서 언급한 시스템 리소스란 CPU, 메모리, Network Bandwidth, HD I/O 등 입니다.
namespaces: 하나의 시스템에서 프로세스 격리시키는 가상화 기술입니다.
위 두 기술은 기존 리눅스의 커널 기술로서 이를 발전시켜 지금의 도커가 개발되었습니다.
리눅스 기반의 두 가지 기술을 windows나 mac 위에서 사용할 수 있는 이유
→ Docker Engine(Docker Server)은 Host OS 위에 리눅스 VM가 설치 된 후, 그 위에 설치됨.
→ 더불어, Docker 컨테이너 내 앱은 위와 같이 설치된 리눅스 VM 위의 리눅스 커널을 걸쳐 작동함.

라. 개발환경과 운영환경에서 다른 서버를 사용하는 이유

개발환경의 특성 상, 개발서버는 소스 변경 시 자동으로 앱 전체를 재빌드하여 변경 부분을 즉각 반영하는 기능이 필요.
운영환경에서는 위에서 언급한 기능이 필요 없음. 불필요한 기능을 제거하여 운영환경에 특화된 웹 서버 이용 시 성능 향상.

2. 도커 클라이언트 명령어

가. client 명령의 동작 원리

docker run alpine ls
→ docker(docker client 언급), run(컨테이너 생성 및 실행), alpine(본 컨테이너를 위한 이미지), ls(파일 목록)
→ 해석: docker client에 다음이 명령어 입력에 따라 도커 서버로 전송됨, 도커 서버에서 컨테이너생성을 위한 이미지가 내부에 캐쉬되어 있는 지 확임함. 없을 경우 허브에서 가져오고 있다면 해당 이미지로 컨테이너 생성. 하드디스크에 해당 이미지 내 파일스냅샷이 저장됨. 이미지 내부의 시작 명령어 대신 ls 명령어에 따라 프로그램 동작
→ 이미지 내부의 시작 명령어 대신 ls 명령어를 실행할 수 있는 이유: 이미지 내 파일 스냅샷에 ls 사용을 유도하는 파일이 있음. 이미지 내 파일에 따라 입력 가능한 명령어에 제한.
예를 들어, hello-world 이미지의 경우 ls 명령 사용 불가, 관련 명령어 유도 파일이 없어서

나. docker process 확인

docker ps
ps: process status
Container ID: 컨테이너 고유 해쉬값, Image: 컨테이너 생성 시 사용한 도커 이미지, Status: 컨네이너 상태(Up 실행 중, Exited 종료, Pause 일시정지), Ports: 컨테이너가 개방한 포트와 호스트에 연결된 포트(미설정 시 출력 X),
names: 컨테이너 고유 이름, 변경 가능
docker rename original-name changed-name
docker ps -a: 모든 컨테이너 나열

다. docker 컨테이너의 생명주기

run === create + start
docker create 이미지: 컨테이너 생성 및 파일 스냅샷을 하드디스크에 할당, 컨테이너 아이디값 반환
docker start 아이디: 컨테이너 이미지에 명령어를 할당하여 프로그램 시작
→ docker start -a 아이디 일부: a는 attach의 줄임말로 아이디의 일부만 입력해도 특정 프로세스 실행 가능
docker stop 아이디: 컨테이너를 Gracefully stop, sigterm 메세지를 보내서 현재 진행 중인 작업을 완료시킨 후 sigkill 메세지를 보내서 컨테이너 중지
docker kill 아이디: 컨테이너를 즉시 stop, 즉시 sigkill 메세지를 보내서 컨테이너 중지
docker rm 아이디: 컨테이너가 중지된 상태에서 삭제 가능
→ docker ps -a -q: 모든 컨테이너 삭제
→ docker rmi 이미지 id: 이미지 삭제
docker system prune: 한번에 컨테이너, 이미지, 네트워크 모두 삭제
→ 작동 중인 컨테이너에 영향 X

라. 동작 중인 컨테이너에 명령

docker exec 아이디: 실행 중인 컨테이너에 명령어 전달
특정 터미널에서 레디스 서버 실행(docker run rdis) 시킨 후, 다른 터미널로 클라이어트 실행 시 작동 X
→ 각기 다른 컨테이너에서 작동하기 때문에 동작 불가. 이를 해결하기 위해 서버가 실행되고 있는 컨테이너에 레디스 클라이언트 실행. exec 활용
→ Redis(Remote Dictionary Server): key-value memory storage style NOSQL
→ Redis 장점: DB 내 데이터 저장 X, 메모리에 저장하기 때문에 빠르게 처리 / 더불어 데이터 영속적 보관 가능(비록 메모리에 저장하지만) 서버 재부팅 후 데이터 유지 가능
docker exec -it 아이디 redis-cli
→ it flag: (interactive terminal) it 입력에 따라 client 실행 후 관련 명령 입력 가능, 미사용시 client-side 명령 입력 불가
docker exec -it 아이디 sh: 동작 중인 컨테이너의 명령어 전달체계를 sh로 변환, docker를 포함한 고정적인 전달부분 생략
ex) MySQL 컨테이너(mysql_docker)에 bash 명령 실행: docker exec -i -t mysql_docker bash
→ sh terminal 나오기: ctl + d

3. 도커 이미지 만들기

가. 도커 이미지 생성순서

1.
Docker file 작성: Docker file은 Docker Image를 만들기 위한 설정 파일임. 컨테이너의 동작 관련 설정이 정의됨
2.
도커 클라이언트: Docker File에 입력된 것이 도커 클라이언트에 전달됨
3.
도커 서버: 도커 클라이언트에 전달된 내용에 대해 작업
4.
이미지 생성

나. Docker file 작성

1.
베이스 이미지 명시
2.
추가적으로 필요한 파일을 받기 위한 명령어 명시
3.
컨테이너 시작 시 실행할 명령어 명시
파일 작성 전, 도커 이미지에 필요한 것이 무언인지 설계
베이스 이미지란 여러 개의 레이어로 구성된 도커 이미지 안에서 기반 레이어, OS 명시를 해줌
## hello를 출력하기 위한 Docker file 작성 # 베이스 이미지 명시 FROM alpine # 추가적으로 필요한 파일 다운로드, hello 출력 시 추가적으로 필요한 파일 X # Run command # 컨테이너 시작 시 실행될 명령어 명시 CMD ["echo", "hello"]
Docker
복사

다. Docker file로 Docker image 만들기

현재 dir 안의 docker file을 찾아서 실행: docker build ./
1.
임시 컨테이너 생성 후 베이스 이미지의 파일 스냅샷을 임시 컨테이너의 하드로 할당
2.
임시 컨테이너에 새로운 명령어 및 파일 스냅샷 이동
3.
임시 컨테이너를 기반으로 만들고자 했던 Docker image 생성
4.
임시 컨테이너 삭제

라. 결과물 출력 및 image naming

docker run -it 아이디: Docker file로 만든 Docker image 실행
image naming: docker build -t 도커아이디/저장소(or 프로젝트 이름):버전
→ t는 tag의 약자
ex) 생성: docker build -t gentlemj/hello:latest ./
실행: docker run -it gentlemj/hello

4. 도커 활용 간단한 Node.js 앱 만들기

가. Node.js 앱 실행

base image로 node:10 사용
base image를 기반으로 Docker image 생성 시 HD로 전달되는 파일에 package.json을 비롯하여 Docker file이 있는 디렉토리의 필수 파일들이 불포함됨
→ COPY ./ ./ 앞의 명령어를 작성하여 HD로 전달되는 파일에 현재 디렉토리 내 모든 파일을 포함시킴
컨테이너 내 네트워크와 로컬에서 사용하는 네트워크를 mapping하기 위해 docker run 명령에 다음을 추가함.
→ docker run -p 5000:8080 gentlemj/nodejs ./
→ 5000은 localhost port num, 8080은 server.js에 명시한 컨테이너 네트워크 포트, p는 포트
FROM node:10 COPY ./ ./ # express 모듈을 사용하기 위해 npm install로 관련 모듈 설치 필요 RUN npm install # server.js 실행 CMD ["node", "server.js"]
Docker
복사

나. 실행 관련 참고사항

working directory 명시 필요
→ 명시를 안하면 앱 실행 및 관리에 불필요한 파일들까지 컨테이너 root dir에 나열되므로 관리에 불편
→ COPY 시 base img에 이미 같은 이름의 폴더나 파일이 있다면 COPY됨에 따라 덮어씌워짐... 의도치 않은 결과 야기 가능
→ WORKDIR 명시하면 COPY된 파일을 WORKDIR에 저장, WORKDIR를 컨테이너 실행 시 시작점으로 설정
FROM node:10 WORKDIR /usr/src/app COPY ./ ./ RUN npm install CMD ["node", "server.js"]
Docker
복사
소스코드 일부 변경 부분을 반영하기 위해 모든 종속성(dependancies) 다운로드
→ 비효율적(소스코드와 관련없는 종속성 모두 포함된 이미지를 생성하고 컨테이너를 실행
→ 아래과 같이 COPY 코드의 순서를 바꿔서 해결
→ 기존 코드의 경우 npm install은 그 위의 COPY 범위 안에서 변경사항이 발생하면 해당 범위의 모든 파일을 다운로드 함. 만약 package.json을 먼저 COPY한다면 server.js에서 발생한 코드 변경사항이 반영이 안되어 package.json 내 종속성은 그대로 둔다.
FROM node:10 WORKDIR /usr/src/app COPY package.json ./ RUN npm install COPY ./ ./ CMD ["node", "server.js"]
Docker
복사
Docker Volume
→ COPY의 경우 로컬 파일을 도커 컨테이너 안에 복사함. Volume 플래그를 사용하면 도커 컨테이너에 필요한 파일을 로컬에서 참조해서 사용함
→ Volume의 장점은 소스코드가 바뀐 경우, 빌드를 생략하고 실행 명령(run)만으로 변경사항이 반영됨.
→ docker run -d -p 5000:8080 -v /usr/src/app/node_modules -v $(pwd):/usr/src/app gentlemj/nodejs
→ 포트 뒤 경로는 참조를 생략하는 폴더 / 뒤의 경로는 참조할 경로

5. Docker know-how by 이진석

가. 주요 명령어

도커 컨테이너의 실행 중단에 따라 도커 이미지 삭제 명령
→ 컨테이너는 쓰고 버리는 개념이기 때문에 실행 중단에 따라 이미지를 삭제하는 것이 컨테이너 관리면에서 편리함
docker run --rm <container-name>
container image에 태그 추가 명령
→ 이미지 관리의 편의를 위해 --name 옵션 활용하여 태그 추가
docker run --rm --name <container-name> <container-tag>
docker container ls docker <container> ps docker <container> stop zen_lumiere docker <container> rm zen_lumiere docker images ls
Shell
복사

나. 웹서버 실행

웹서버 실행 명령
→ 웹서버 기준으로 traffic의 network port 지정
→ nginx는 inbound traffic을 80번 포트로 받도록 기본 설정됨
docker run --rm --publish 8000:80 --name nginx firstnginx
→ 웹서버 background 실행 시 --detach 옵션 추가
docker run --rm --detach --publish 8000:80 --name nginx firstnginx
웹서버 정지, 삭제
→ 정지: docker stop <container-tag>
→ 삭제: docker rm <container-tag>
--volume 옵션
docker run -d -p 8080:80 --volume `pwd`/html:/usr/share/nginx/html --name mynginx nginx
interative with shell
→ -it 옵션과 함께 sh를 붙이면 이미지를 백그라운드로 돌리고 cmd 사용 가능
docker run -d -p 8080:80 -it nginx sh

다. 개발용 Dockerfile 작성

RUN 명령 뒤 &&의 의미는 앞의 명령의 정상 실행 확인에 따라 뒷 명령을 실행한다는 것
ADD: 호스트 경로의 파일을 컨테이너의 특정 경로로 복사
EXPOSE: container에게 할당할 포트번호 지정
→ 실서비스에서는 gunicorn이나 uwsgi를 사용
FROM ubuntu:18.04 RUN apt-get update && apt-get install -y python3-pip python3-dev && apt-get clean WORKDIR /code ADD ./backend/requirements.txt /code/ RUN pip3 install -r requirements.txt ADD ./backend /code/ EXPOSE 8000 CMD ["python3", "/code/manage.py", "runserver", "0.0.0.0:8000"]
Docker
복사

라. Docker Build & Run

Docker Image Build
docker build --tag <docker-image-name> <docker-image-tag> <Dockerfile 경로>
→ docker-image-tag 생략시 latest로 붙어서 생성됨
docker build --tag test_dj .
Docker Image 확인
docker images
Docker Run
docker run --rm --publish 9000:8000 test_dj

마. Docker Hub 활용

docker login
docker push <docker-image-name>
→ docker image name은 tag 명령으로 수정 가능
docker tag <기존 이름> <변경할 이름>
docker tag <IMAGE ID> <변경할 이름>
→ 예시
# 명령 docker tag 007df4c4f543 997494235799.dkr.ecr.us-east-1.amazonaws.com/om-log-server-staging-java # 이하 결과 REPOSITORY TAG IMAGE ID CREATED SIZE 997494235799.dkr.ecr.us-east-1.amazonaws.com/om-log-server-staging-java latest 007df4c4f543 2 minutes ago 747MB
Plain Text
복사
docker hub 내 이미지 이름과 태그의 조합으로 컨테이너 실행 가능
docker run --rm --publish 9000:8000 <docker-image-name>:<tag>
docker run --rm --publish 9000:8000 test_dj:0.1

기타

가. MySQL 초기 설정

나. Redis 초기 설정

다. ElasticSearch 초기 설정

이하 링크의 Setting 참고

라. RabbitMQ 설정

이하 링크의 RabbitMQ 참고

마. EC2 t2 micro docker 설치하기

Reference