도커 엔진에서 사용하는 기본 단위는 이미지와 컨테이너입니다.
도커 이미지
테이너를 생성할 때 필요한 요소. 가상 머신을 생성할 때 사용하는 iso 파일과 비슷한 개념.
여러 개의 계층으로 된 바이너리 파일로 존재, 컨테이너를 생성하고 실행할 때 읽기 전용으로 사용.
도커 명령어로 내려받을 수 있으므로 별도로 설치할 필요 없음.
이미지 이름은 기본적으로 [저장소 이름]/[이미지 이름]: 태그 형태로 구성됩니다.
ex) alicek106/ubuntu:14.04
- 저장소: 이미지가 저장된 장소, 생략가능.
- 이미지: 이미지가 어떤 역할을 하는지 나타냄. 생략 불가.(ex)우분투 컨테이너를 생성하기 위한 이미지)
- 태그: 이미지의 버전 관리, 혹은 리비전 관리에 사용. (일반적으로 버전 명시하나 태그를 생략하면 도커 엔진은 이미지와 태그를 latest 인식
도커 컨테이너
도커 이미지
기본적인 리눅스 운영체제부터 각종 애플리케이션, 빅데이터 분석도구까지 여러 종류가 있음
도커 컨테이너
도커 이미지로 이미지의 목적에 맞는 파일이 들어있는 파일시스템 격리된 시스템 자원 및 네트워크를 사용할 수 있는 독립된 공간 생성
생성될 때 사용된 도커 이미지의 종류에 따라 알맞은 설정과 파일을 가지고 있음
ex) 웹 서버 도커 이미지로부터 여러 개의 컨테이너 생성
=> 생성된 컨테이너의 개수만큼 웹 서버 생성
=> 컨테이너들은 외부에 웹 서비스를 제공
(도커 이미지와 컨테이너는 1:N 관계)
이미지를 읽기 전용으로 사용, 이미지에서 변경된 사항만 컨테이너 계층에 저장
=> 컨테이너에서 뭘 해도 이미지의 영향 X
각기 독립된 파일시스템 제공, 호스트와 분리돼 있으므로 특정 컨테이너에서 어떤 애플리케이션을 설치, 삭제해도 다른 컨테이너와 호스트는 변화 X
도커 사용법
컨테이너 생성
docker run -i -t ubuntu:14.04
docker run: 컨테이너 생성, 실행
ubuntu:14.04: 컨테이너 생성 위한 이미지의 이름
-i, -t: 컨테이너와 상호입출력 가능하게 함
이 명령어를 통해 컨테이너를 생성 및 실행과 동시에 컨테이너 내부로 들어왔습니다.
기본사용자 root, 호스트 이름은 무작위의 16진수 해시값(컨테이너의 고유한 ID의 앞부분)
컨테이너와 호스트의 파일시스템은 서로 독립적이라 아무것도 설치되지 않은 상태.
Ctrl + D, exit: 컨테이너 내부에서 빠져나옴 + 컨테이너 정지
Ctrl + P, Q: 컨테이너 내부에서 빠져나옴 (정지되지 않은 채)
이번에는 CentOS 이미지를 사용해 컨테이너를 생성해 보겠습니다.
pull: 이미지를 내려받을 때 사용
images: 이미지 목록 출력
docker create -i -t --name mycentos centos:7
create 명령어로도 컨테이너 생성 가능. but run처럼 컨테이너 내부로 들어가지는 않음.
--name: 컨테이너의 이름 설정
start: 컨테이너 시작
attach: 컨테이너 내부로 들어감
run: pull, create, start 명령어를 일괄적으로 실행한 후, attach가 가능한 컨테이너라면 내부로 들어감
create: pull, create
docker start dd06c5cn6bf4
docker start dd0
위의 코드처럼 컨테이너를 대상으로 하는 모든 명령어는 컨테이너의 이름대신 ID를 쓸 수 있음(앞의 2~3글자도 입력가능)
ps: 컨테이너 목록 확인, 정지되지 않은 컨테이너만 출력.
ex) exit를 통해 빠져나오면 X, Ctrl + P, Q는 목록에 출력
정지된 컨테이너도 모두 포함하려면 -a 옵션 추가
- CONTAINER ID: 컨테이너에 자동 할당되는 고유 ID, 일부만 나타나며 inspect 명령어를 통해 전체 확인 가능
- IMAGE: 컨테이너를 생성할 때 사용된 이미지의 이름
- COMMAND: 컨테이너가 시작될 때 실행될 명령어
- CREATE: 컨테이너가 생성되고 난 뒤 흐른 시간을 나타냄
- STATUS: 컨테이너 상태 (Up: 실행 중, Exited:종료, Pause: 일시 중지)
- PORTS: 컨테이너가 개방한 포트와 호스트에 연결한 포트를 나열
- NAMES: 컨테이너의 고유한 이름, rename 명령어로 변경 가능
rm: 더 이상 사용하지 않는 컨테이너 삭제(한 번 삭제한 컨테이너는 복구 x
ex) ubuntu, CentOS는 가능
실행 중인 컨테이너는 삭제할 수 없으므로 실행 중이었던 컨테이너를 멈추고 삭제해 주었습니다.
하지만 실행 중인 컨테이너도 -f 옵션을 사용하면 강제로 삭제가 가능합니다.
docker container prune
prune 명령어를 사용하면 모든 컨테이너를 한 번에 삭제할 수 있습니다.
docker ps -a -q
-a: 컨테이너 상태와 관계없이 모든 컨테이너 출력
-q: 컨테이너의 ID만 출력
=> 이 옵션들을 사용해 컨테이너를 삭제할 수도 있습니다.
docekr stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
위처럼 명령어를 사용하면 실행 상태와 관계없이 모든 컨테이너를 정지하고 삭제할 수 있습니다.
컨테이너 외부 노출
컨테이너는 가상 IP 주소를 할당받습니다. 기본적으로 172.17.0.x의 IP를 순차적으로 할당합니다.
도커의 NAT IP인 172.17.0.2를 할당받은 eth0 인터페이스와 로컬 호스트인 lo 인터페이스가 있습니다.
아무 설정을 하지 않았다면 이 컨테이너는 외부에서 접근할 수 없으며 도커가 설치된 호스트에서만 접근할 수 있습니다.
외부의 컨테이너에서 애플리케이션을 노출하기 위해서는 eth0의 IP와 포트를 호스트 IP와 포트에 바인딩해야 합니다.
docker run -i -t --name myserver -p 192.168.0.100:7777:80 ubuntu:14.04
-p [호스트의 포트]:[컨테이너의 포트] : 컨테이너의 포트를 호스트의 포트와 바인딩해 연결할 수 있게 설정
호스트의 7777번 포트를 컨테이너의 80번 포트와 연결하려면 7777:80과 같이 입력하고,
특정 IP의 포트를 사용하려면 192.168.0.100:7777:80과 같이 바인딩할 IP와 포트를 명시합니다.
또한 여러 개의 포트를 외부에 개방하려면 -p 옵션을 여러 번 써서 설정합니다.
컨테이너를 생성 후 내부로 들어오면 순수 OS의 이미지만 담겨있기 때문에 아파치 웹 서버를 설치하겠습니다.
apt-get update
apt-get install apache2 -y
service apache2 start
아파치 웹 서버가 잘 실행되었는지 확인해 보겠습니다. [도커 엔진 호스트의 IP]:80으로 접근합니다.
docker run -i -t --name mywebserver -p 7777:80 ubuntu:14.04
웹사이트로도 접속이 가능한데 저는 이 명령어로 컨테이너를 만들었기 때문에 http://localhost:7777로 접속했습니다.
아파치 서버가 설치된 곳은 컨테이너 내부이므로 호스트에는 어떠한 영향도 주지 않습니다.
호스트의 IP, 포트를 컨테이너 IP, 포트로 연결한다는 개념은 매우 중요합니다.
아파치 웹 서버는 172 대역을 가진 컨테이너의 NAT IP와 80번 포트로 서비스하므로,
여기에 접근하려면 172.17.0.x:80의 주소로 접근해야 합니다.
그러나 도커의 포트포워딩 옵션인 -p를 써서 호스트와 컨테이너를 연결했으므로 호스트의 ip와 포트를 통해 172.17.0.x:80으로 접근할 수 있습니다.
80번 호스트 포트 -> (포트포워딩) -> 80번 컨테이너 포트 -> (포트포워딩) -> 웹 서비스(80번 포트)
만약 -p 80:81과 같이 입력했다면 외부에서 웹 서버에 접근하지 못합니다.
호스트의 80번 포트와 연결된 컨테이너의 포트는 81번이 될 것이고, 81번 포트는 어떠한 서비스도 제공하도록 설정돼있지 않기 때문입니다.
컨테이너 애플리케이션 구축
여러 에이전트나 데이터베이스 등과의 연결을 통해 만들어진 하나의 서비스를 컨테이너화 할 때 여러 개의 애플리케이션을 한 컨테이너에 설치할 수도 있습니다.
but 컨테이너에 애플리케이션을 하나만 동작
=> 컨테이너 간의 독립성 보장 + 애플리케이션의 버전 관리 + 소스코드 모듈화 등이 더욱 쉬워짐.
ex)
1) All in one 컨테이너 (데이터베이스 + 웹 서버)
2) 분리된 애플리케이션 컨테이너 (데이터베이스 | 웹 서버)
2번이 도커 이미지를 관리하고 컴포넌트의 독립성을 유지하기 쉽습니다.
그럼 데이터베이스와 워드프레스 웹 서버 컨테이너를 연동해 워드프레스 기반 블로그 서비스를 만들어보겠습니다.
docker pull --platform linux/amd64 mysql
mysql을 사용하기 위해서 이미지를 설치합니다. 저는 맥북 m1을 사용하고 있기 때문에 플랫폼을 지정해서 설치해 줍니다. (Intel, Apple ver 중 선택해야 함)
docker run -d \
--name wordpressdb \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpress \
mysql
이를 통해 mysql 이미지를 사용해 데이터베이스 컨테이너를 생성했습니다.
docker run -d \
-e WORD_DB_PASSWORD=password \
--name wordpress \
--link wordpressdb:mysql \
-p 80 \
wordpress
워드프레스 이미지를 이용해 워드프레스 웹 서버 컨테이너를 생성합니다.
웹 서버 컨테이너의 -p 옵션에서 80을 입력했으므로 호스트의 포트 중 하나와 컨테이너의 80번 포트가 연결됩니다.
호스트의 50000번 포트와 컨테이너의 80번 포트가 연결된 것을 확인할 수 있습니다.
docker port wordpress
port 명령어를 통해 wordpress라는 이림의 컨테이너가 사용 중인 호스트의 포트를 출력할 수 있습니다.
[호스트 IP]:[포트 번호]에 접근해서 결과를 확인해 보겠습니다.
http://localhost:50000에 접속한 결과 워드프레스 컨테이너가 성공적으로 생성된 것을 확인할 수 있습니다.
앞서 run 명령어를 사용할 때 전에 사용하지 않았던 옵션을 사용했습니다.
-d: -i -t가 컨테이너 내부로 진입하도록 attach 가능한 상태로 설정한다면 -d는 Detached 모드로 컨테이너를 실행합니다.
Detached 모드는 컨테이너를 백그라운드에서 동작하는 애플리케이션으로써 실행하도록 설정합니다.
-i -t 옵션과는 다르게 입출력이 없는 상태로 컨테이너를 실행합니다.
포그라운드로 실행되기 때문입니다.
그래서 Detached 모드인 컨테이너는 반드시 컨테이너 내에서 프로그램이 실행돼야 하며, 포그라운드 프로그램이 실행되지 않으면 컨테이너는 종료됩니다.
테스트를 위해 Detached 모드로 run 명령어를 실행했습니다.
때문에 컨테이너가 바로 생성됐더라도 종료되므로 ps 명령어로는 확인할 수 없었고,
-a 옵션을 통해 생성된 컨테이너의 상태를 확인할 수 있었습니다.
컨테이너 내부에 터미널을 차지하는 포그라운드로써 동작하는 프로그램이 없으므로 컨테이너는 시작되지 않습니다.
그렇다면 반대로 mysql 컨테이너를 -i -t 옵션으로 생성하면 어떻게 될까요?
docker run -i -t \
--name mysql_attach_test \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpress \
mysql
이를 실행하면 하나의 차지하는 mysqld 플그램이 포그라운드로 실행된 로그를 볼 수 있습니다.
MySQL 이미지는 컨테이너가 시작될 때 mysqld가 동작하도록 설정되어 있기 때문입니다.
이 상태로는 상호입출력이 불가능하고, 포드라운드 모드로 동작하는 것만 지켜볼 수 있습니다.
-e: 컨테이너 내부 환경변수 설정
실제로 환경변수가 설정된 것을 확인할 수 있습니다.
이렇게 명령어를 사용하기 위해서는 상호 입출력이 가능한 배시 셸을 사용할 수 있는 환경이 필요합니다.
이를 위해서 docker attach 명령어로 컨테이너 내부로 들어가야 하지만,
-d 옵션으로 생성했기 때문에 실행 중인 프로그램의 로그를 보는 것 밖에 할 수 있는 게 없습니다.
그러나 exec 명령어를 사용하면 컨테이너 내부의 셸을 사용할 수 있습니다.
exec: 컨테이너 내부에서 명령어를 실행한 뒤 그 결괏값을 반환받을 수 있음
-i -t 옵션을 사용해 /bin/bash를 상호 입출력이 가능한 형태로 exec 명령어를 사용
옵션을 추가하지 않고 단순히 exec만 쓰면 컨테이너 내부에서 실행한 명령어에 대한 결과를 반환
A 컨테이너에서 B 컨테이너로 접근하는 방법 중 가장 간단한 것은 NAT로 할당받은 내부 IP를 쓰는 것.
B 컨테이너의 IP: 172.17.0.3
-> A 컨테이너는 이 IP를 써서 B 컨테이너로 접근할 수 있음.
그러나 도커 엔진은 컨테이너에게 내부 IP 172.17.0.2, 3, 4... 와 같이 순차적 할당
이는 컨테이너가 시작할 때마다 재할당됨. 매번 변경되는 컨테이너의 IP로 접근하기는 어려움
--link: 내부 IP를 알 필요 없이 컨테이너의 별명(alias)으로 접근하도록 설정
컨테이너 간에 이름을 서로 찾을 수 있게 도와줌. but deprecated 된 옵션, 추후 삭제될 수 있음
=> 브리지 네트워크를 사용하는 것을 권장.
ex)
docker run -d \
-e WORD_DB_PASSWORD=password \
--name wordpress \
--link wordpressdb:mysql \
-p 80 \
wordpress
이를 통해 mysql이라는 호스트명을 통해 접근 가능.
즉, mysql -> wordpressdb 컨테이너의 내부 IP로 접근 가능
출처: 시작하세요! 도커 / 쿠버네티스
'Docker&Kubernetes' 카테고리의 다른 글
[Docker] 도커 엔진 (컨테이너 CPU 제한, 도커 이미지 만들기, 커밋) (0) | 2024.03.11 |
---|---|
[Docker] 도커 엔진 (컨테이너 로깅, logs, syslog, memory) (0) | 2024.03.01 |
[Docker] 도커 엔진 (Volume, network, bridge, MacVLAN) (0) | 2024.02.21 |
[Docker] 도커란? (1) | 2024.01.19 |