🐳도커(Docker)란?
도커는 컨테이너 기술을 기반으로 하는 일종의 가상화 플랫폼이다.
리눅스 컨테이너에 여러 기능을 추가함으로써 애플리케이션을 컨테이너로서 좀 더 쉽게 사용할 수 있게 만들어진 오픈 프로젝트 / 기존에 쓰이던 가상화 방법인 가상 머신(VirturalBox, VMware 등) 보다 성능의 손실이 훨 씬 덜하다.
📚 가상화 vs 컨테이너
가상 머신(VirturalBox, VMware 등)
- 하나의 하드웨어에 여러 개의 가상 머신으로 분할해 효율적으로 사용할 수 있는 기술
- 분할 된 가상 머신들은 각각 독립적인 환경으로 구동됨
- 기존 환경( Host OS )
분할 된 각각의 환경( Guest OS ) - Guest OS는 하이퍼바이저에 의해 생성되고 관리됨 → 항상 하이퍼바이저를 거쳐야함
- 속도 저하,
가상 머신 배포 시 이미지의 크기가 매우 커짐,
환경 구축 파일이 모두 들어가 있기 때문에 OS 크기가 매우큼
컨테이너
- 가상의 OS를 만드는 것이 아니라 베이스 환경의 OS는 공유하면서 필요한 프로세만 격리
- 커널을 공유하기 때문에 Host OS의 기능을 모두 사용할 수 있음
- 애플리케이션에 필요한 파일, 특정 라이브러리 등 종속 항목만 포함 하기 때문에 이미지의 용량이 매우 작아짐,
운영체제가 아닌 프로세스이기 때문에 하이퍼바이저를 거칠 필요가 없음 → 속도가 매우 빨라짐
📚 도커의 장점
애플리케이션의 개발과 배포가 편해짐
- 도커 컨테이너는 서버 부팅 시 실행되는 운영체제인 Host OS 위에 실행되는 격리된 공간
→ 컨테이너 자체에 특별한 권한을 주지 않는 한, 컨테이너 내부에 소프트웨어를 설치하고 설정 파일을 수정해도 Host OS에는 영향을 끼치지 않음 - 독립된 개발 환경을 보장 받을 수 있음
- 작업을 마치고 이를 서버 환경에 배포할 때 해당 컨테이너를 ‘도커 이미지’라고 하는 일종의 패키지로 만들어 서버 환경에 전달하기만 하면 됨
→ 개발 시 사용했던 환경을 다른 서버에서도 컨테이너로서 똑같이 복제할 수 있음 - 도커 이미지는 가상 머신의 이미지와 달리 커널을 포함하고 있지 않기 때문에 이미지 크기가 크지 않음
- 이미지 내용을 레이어 단위로 구성하여 중복되는 레이어를 재사용할 수 있어 애플리케이션 배포 속도가 매우빨라짐
여러 애플리케이션의 독립성과 확장성이 높아짐
모놀리스(Monolith) 애플리케이션
- 소프트웨어의 여러 모듈이 상호 작용하는 로직을 하나의 프로그램 내에서 구동시키는 방식
- 소규모 서비스에서는 이 방식이 어울릴지도 모르지만, 서비스 기능이 복잡해지고 거대해 질수록 소프트웨어 자체의 확장성과 유연성이 줄어듦
마이크로 서비스(Microservice)
- 여러 모듈을 독립된 형태로 구성하기 때문에 언어에 종속되지 않고 변화에 빠르게 대응할 수 있음
- 각 모듈의 관리가 쉬워짐
- 컨테이너는 수초 내로 생성, 시작이 가능할 뿐만 아니라 여러 모듈에게 독립된 환경을 동시에 제공할 수 있기 때문에 마이크로서비스 구조에서 가장많이 쓰이고있는 가상화 기술임
📚 도커 엔진(Docker Engine)
도커는 리눅스 컨테이너를 제어하는 API를 Go언어로 구현한 libcontainer를 사용하기 때문에 대부분의 리눅스 운영체제에서 사용할 수 있음 → 대표적인 리눅스 운영체제로는 CentOS, 우분투 등이 있음
도커 이미지
- 컨테이너를 생성할 때 필요한 요소
- 여러 개의 계층으로 된 바이너리 파일로 존재
- 컨테이너를 생성하고 실행할 때 읽기 전용으로 사용됨
- 이미지는 도커 명령어로 내려받을 수 있으므로 별도로 설치할 필요 없음
- [저장소 이름]/[이미지 이름]:[태그]의 형태로 구성
- 저장소(Repository) : 이미지가 저장된 장소 (생략가능)
- 이미지 이름 : 해당 이미지의 역할을 나타냄 (생략불가)
- 태그 : 이미지의 버전 관리, 혹은 리비전(Revision) 관리에 사용 (생략 시 latest로 인식함)
도커 명령어로 컨테이너 다루기
도커 버전확인
# docker -v
도커 이미지 다운만 받기
# docker pull {이미지명}:{태그}
도커파일로 이미지 생성
Dockerfile 파일이 있는 디렉토리 기준. 마지막의 ' . ' 이 상대주소
# docker build -t {이미지명} .
컨테이너 생성
run : 생성과 동시에 컨테이너 내부로 들어감
→ start, attach 실행
# docker run -i -t [이미지이름:태그]
create : 컨테이너만 생성하고 내부로 안 들어감
→ 도커 이미지를 pull 한 뒤 컨테이너만 생성 할 뿐 start, attach 실행하지 않음
# docker create -i -t {옵션 (ex)--name [생성할 이름]} [이미지이름:태그]
start , attach
// 만들어진 컨테이너 시작하기(이미지에 CMD로 지정해놓은 작업 시키기
# docker start [컨테이너이름]
// 컨테이너로 들어가기(컨테이너 내 CLI 사용하기)
# docker attach [컨테이너이름]
-i , -t 옵션
-i : 상호 입/출력
-t : tty 활성화해서 배시(bash) 셸을 사용하도록 컨테이너 설정
# bdocker run 사용 시 이 두 옵션을 사용하지 않으면 셸을 정상적으로 사용할 수 없음
동작중인 컨테이너 재시작
# docker restart {컨테이너 id 또는 이름}
컨테이너 내부에서 나오기
컨테이너 정지 시키면서 빠져나오기
exit
Ctrl + D
컨테이너 정지 안하고 빠져나오기
Ctrl + P, Q
도커 엔진에 존재하는 이미지 목록
# docker images
컨테이너 목록
정지되지 않은 컨테이너만 출력
# docker ps
정지된 컨테이너도 모두 포함하여 출력(-a 옵션)
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8828a383f936 ubuntu:22.04 "bash" 25 hours ago Up 25 hours hopeful_lovelace
- CONTAINER ID : 컨테이너에게 자동으로 할당되는 고유한 ID ⇒docker ps 에서는 ID 일부분만 출력되는데 컨테이너 정보를 확인하기 위해선 # docker inspect [컨테이너 이름] | grep Id 사용하여 풀 ID 확인 가능
- IMAGE : 컨테이너를 생성할 때 사용된 이미지 이름
- COMMAND : 컨테이너가 시작될 때 실행될 명령어 ⇒ 대부분 이미지에 미리 내장돼있기 때문에 별도 설정은 필요없음
- CREATED : 컨테이너가 생성되고 난 뒤 흐른 시간
- STATUS : 컨테이너의 상태
- Exited… 정지 상태
- UP …seconds 실행중 상태
- Pause 중지 상태
- PORTS : 컨테이너가 개방한 포트와 호스트에 연결한 포트를 나열함
- NAMES : 컨테이너의 고유한 이름
⇒ --name 옵션으로 이름을 설정하지 않으면 도커 엔진이 임의로 형용사와 명사를 무작위 조합해 이름을 설정함
⇒ docker rename [기존컨테이너이름] [변경할컨테이너이름] 사용하여 컨테이너 이름 변경 가능
컨테이너 삭제
# docker rm
실행중인 컨테이너는 삭제 불가하여 stop 명령어로 중지 시킨 후 삭제
# docker stop mycentos
# docker rm mycentos
실행중인 컨테이너 바로 삭제
# docker rm -f mycentos
모든 컨테이너 한번에 삭제
-> -a : 컨테이너 상태와 관계없이 모든컨테이너 / -q : 컨테이너 ID만 출력
# docker container prune
# docker ps -a -q
컨테이너의 실행 상태와 관계없이 모든 컨테이너를 정지하고 삭제
# docker stop $(docker ps -a -p)
# docker rm $(docker ps -a -q)
rmi : 이미지 삭제
# docker rmi {옵션} {이미지 id}
exec : 이미 실행된 특정 컨테이너 환경을 디버깅하는 용도
# docker exec [컨테이너ID] [COMMAND]
// 해당 컨테이너 ID 실행 후 COMMAND 명령어 실행
# docker run 은 새로 컨테이너를 생성하는 용도
logs : 도커 로그 확인
# docker logs [컨테이너ID]
도커 포트 설정
출처 : https://youtu.be/SJFO2w5Q2HI 생활코딩유튜브
컨테이너는 가상 머신과 마찬가지로 가상 IP 주소를 할당받음 ( 172.17.0.x 의 IP를 순차적으로 )
컨테이너의 네트워크 인터페이스를 확인
# ifconfig
-p : 컨테이너의 포트를 호스트의 포트와 바인딩해 연결할 수 있게 설정
# -p [호스트의 포트]:[컨테이너의 포트]
// 예) 7777:80 -> 호스트의 7777번 포트를 컨테이너 80번 포트와 연결
# -p [특정IP]:[호스트의 포트]:[컨테이너의 포트]
// 예) 192.168.0.100:7777:80
# -p [호스트의 포트]:[컨테이너의 포트] -p [특정IP]:[호스트의 포트]:[컨테이너의 포트]
// 여러 개의 포트를 외부에 개방
// 예) -p 3306:3306 -p 192.168.0.100:7777:80
# -p 80
// 컨테이너의 80번 포트를 쓸 수 있는 호스트의 포트 중 하나와 연결
// 어느포트와 연결했는지 알 수 없기 때문에 docker ps 명령어로 PORTS 항목 확인 필요
도커 볼륨
도커 이미지로 컨테이너를 생성하면 이미지는 읽기 전용이 되며,
컨테이너의 변경 사항만 별도로 저장해서 각 컨테이너의 정보를 보존한다.
⇒ 도커가 내려가면 컨테이너가 가지고 있는 정보들이 모두 사라짐 ( 도커사용 이유가 없어짐 )
이 때, 도커 볼륨을 사용하여 Host OS와 Docker Container가 같은 디렉터리를 바라보게하여 정보를 둘 다 저장한다.
⇒ 도커가 내려가도 Host OS에 정보가 남아 보존할 수 있음
두 디렉터리를 공유하여 새로 생성한 파일을 두 곳에서 관리할 수 있음
-v
# -v [Host OS 공유 디렉터리(경로)]:[컨테이너 공유 디렉터리(경로)]
// 예) docker run -d -v /root:/app ubuntu:22.04