docker란?

음휘영·2023년 5월 12일
0

docker/kubernetes

목록 보기
2/3

도커(Docker)는 linux 컨테이너를 기반으로하는 오픈소스 가상화 플랫폼이다.
컨테이너는 소프트웨어를 패키지화하여 실행하는데 사용되며, 도커는 이러한 컨테이너를 관리하고 배포하는 도구이다.
도커는 컨테이너 관리 기능 외에도 명령어 입력도구인 CLI와 명령어을 받아들이는 도커 데몬과 이미지를 저장하는 레지스트리로 구성되어있다.
도커와 쿠버네티스를 함께 설치할 경우 쿠버네티스는 컨테이너 오케스트레이션을 위해 도커에 포함된 컨테이너디를 활용한다.

컨테이너란?

가상화 환경에서는 각각의 가상머신이 모두 독립적인 운영체제 커널을 가지고 있기 때문에 그만큼 자원을 더 소모해야 하고 성능이 떨어진다. 하지만 컨테이너 인프라 환경은 운영체제 커널 하나에 컨테이너 여러개가 격리된 형태로 실행되기 때문에 자원을 효율적으로 사용할 수 있고 거치는 단계가 적어서 속도가 훨씬 빠르다.

가상머신(Vertual Machine)
HyperVisor는 컴퓨터가 가지고 있는 인프라 리소스들에 대해 VM별로 배분 하는역할들을 한다. 또한 각 VM에서는 독립적인 OS를 가지고 있어따라서 독립적인 플랫폼을 하나씩 증가시킬 때마다 불필요한 OS계속해서 만들게 되어 확장성이 떨어진다. 또한 메모리나 자원에 관해서 유동적으로 관리 되는게 아니라 처음부터 정해놓고 실행하기에 비효율적이다.

컨테이너(Container)

소프트웨어는 OS와 라이브러리에 의존성을 띈다. 그러므로 하나의 컴퓨터에서 성격이 다른(OS, 라이브 버전이 다른) 소프트웨어를 한번에 실행할 때 어려움을 가질 수 있고, 관련된 구성을 가지기 어렵다.

컨테이너(Container)는 개별 application의 실행에 필요한 실행환경을 독립적으로 운용할 수 있도록 기반환경 또는 다른 실행환경과의 간섭을 막고 실행의 독립성을 확보해주는 운영체계 수준의 격리 기술을 말한다.

컨테이너의 경우 하나의 Host OS위에서 마치 각각의 독립적인 프로그램처럼 관리되고 실행된다. 불필요한 OS만드는작업 및 Infra를 독립적으로 나눌 필요가 없어서 확장성이 좋고 빠르다.

컨테이너는 독립된 애플리케이션의 실행 환경으로 VM보다 메모리를 덜 소모하고, 셋업이 빠르다. 또한 VM과 비교해 크기가 작기 때문에 마이그레이션, 백업, 전송이 쉽고 하드웨어와의 커뮤니케이션이 빨라 전달 시간이 감소할 수 있기 때문에 성능이 효과적이다. 애플리케이션의 배치와 유지보수를 향상시킨다는 장점이 있다.


도커를 사용하는 이유

  • 변화하지 않는 실행환경으로 멱등성을 확보 할 수 있다.
  • 코드를 통한 실행환경 구축 및 어플리케이션 구성이 쉽다.
  • 실행황경과 어플리케이션의 일체화로 이식성이 향상된다.
  • 시스템을 구성하는 어플리케이션 및 미들웨어의 관리 용이성이 높아진다.

웹 어플리케이션 개발을 예로 들면, 도커를 사용하는 경우 로컬개발 환경에서 필요한 어플리케이션을 신속하게 갖출 수 있으며 OS와 상관 없이 도커가 설치된 머신이라면 어디에서든지 배포가 가능해진다. 또한 변화하지 않는 일관된 실행환경이 구축되기 때문에 문제가 되는 원인을 최소화 할 수 있다. 그리고 미들웨어를 포함하는 시스템 구성 또한 설정파일로 정의 할 수 있게된다.
그 밖에도 도커는 도커이미지(Dockerfile)로 구성을 코드로 관리 할 수 있어 빠르고 쉽게 기존 컨테이너를 폐기 및 재구축 할 수 있다.

여러서버에 걸쳐있는 여러 컨테이너를 관리하기 위해 도커 스웜(Docker Swarm) 및 쿠버네티스 같은 도구들을 사용하여 관리를 할 수도 있다.

이러한 장점들을 가진 도커는 운영측면에서나, 배포 및 관리 측면에서나 기존의 가상머신보다 월등하게 편리한 점이 많고, 성능면에서도 확장이 쉽고 오버헤드가 적다는 장점이 있다.


도커 이미지

도커는 이미지라는 패키지 형식을 사용하여 컨테이너를 생성한다. 이미지는 컨테이너를 생성하는데 필요한 모든 설정과 종속성을 포함하고 있고, 재사용이 가능하다. 도커 이미지는 빌드 과정을 통해 생성되며, 도커 레지스트리에서 공유 및 관리되고 있습니다.
레지스트리는 도커 허브에서 받을 수도 있고, 내부에 구축한 레지스트리일 수도 있다. 기본적으로 레지스트리를 지정하지 않으면 기본으로 도커 허브에서 이미지를 찾는다.


도커의 간단한 사용 예제

실습 환경은 rockylinux8 에서 진행했다.

docker 설치 & 레지스트리 설정

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
설치 과정 중 터미널에 GPG key 가 나오는데 docker의 공식 홈페이지와 비교하여 안정성을 확인한다.
060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35

도커 데몬을 재시작하고, 리눅스와 함께 시작하도록 systemd의 유닛에 등록한다.
systemctl start docker
systemctl --now enable docker

docker -v 도커의 버전 확인
docker run hello-world hello world 이미지를 실행해보자

hello-world 이미지가 없기 때문에 도커 레지스트리에서 이미지를 pull 받는 과정을 출력해준다.

//파일을 생성하는 과정을 출력해준다.
1. Docker 클라이언트가 Docker 데몬에 접속했습니다.
2. 도커 데몬이 도커 허브에서 "hello-world" 이미지를 가져옵니다. (amd64)
3. Docker 데몬은 해당 이미지에서 현재 읽고 있는 출력을 생성하는 실행 파일을 실행하는 새 컨테이너를 생성했습니다.
4. Docker 데몬은 해당 출력을 Docker 클라이언트로 스트리밍하여 터미널로 보냈습니다.

보다 야심 찬 것을 시도하려면 다음을 사용하여 Ubuntu 컨테이너를 실행할 수 있습니다 :
$ docker run -it ubuntu bash  //운영체제를 컨테이너화 시킨 후 해당 os 에 접속

docker의 이미지는 registry라고 하는 저장소에 모여있다.
별도의 레지스트리를 지정하지 않으면 도커 허브에서 이미지를 찾아온다.

도커 설치하기

docker ps 실행 중 컨테이너 보기
docker ps -a 중지된 컨테이너까지 모두 보기

docker search nginx 이미지 검색 명령어
-> docker hub와 같은 정보를 가리킨다.

docker pull nginx
이미지의 버전을 명시하지 않으면 docker hub의 최상단에 있는것을 가져온다.

  • 이미지는 여러개의 레이어로 구성되어 있어 레이어마다 pull complete메시지가 발생한다.
  • nginx : latest
    별도의 : (태그) 을 붙이지 않으면 기본으로 latest 태그가 적용된다.
    최신버전, mainline → 패치 곧장 적용 버그 패치, 기능 패치, 업데이트
    Its, stable → 메이저 업데이트, 보안 패치
  • Digest : 이미지의 고유 식별자, 이미지에 포함된 내용과 이미지의 생성환경을 식별할 수 있다.
  • Status : 이미지를 내려받은 레지스트리, 이미지, 태그 등의 상태정보를 확인할 수 있다.

이미지가 레이어로 구성되어 같은 내용의 경우 여러 이미지에 동일한 레이어를 공유하므로 전체 용량이 감소한다. 이미지 업데이트시 변경 내용이 있는 경우 변경된 부분만 추가 하여 레이어로 구성한다.

docker history nginx:stable
docker hostiry nginx:latest
→ 도커 컨테이너 이미지 자체를 만드는 명령을 보여준다.
이처럼 도커로 작성된 컨테이너는 레이어를 재사용하기 때문에 여러 이미지를 내려받더라도 디스크 용량을 효율적으로 사용할 수 있다.

docker images 다운받은 이미지 조회
docker images nginx 다운받은 이미지 필터링 해서 조회


컨테이너 실행하기

docker run -d -p 8080:80 --name hello-nginx --restart always nginx:latest
//-d(--detach) : 컨테이너를 백그라운드에서 구동한다는 의미
//-p(--publish) : 외부에서 호스트로 보낸 요청을 컨테이너 내부로 전달하는 옵션
//--restart always : 컨테이너의 재시작과 관련된 정책 옵션
//-p 8080:80 : 컨테이너 외부의 8080포트와 내부의 80포트를 매칭하여 실행시킨다.

run 명령어와 함께 사용할 수 있는 옵션에는 다음과 같이 있다.

이렇게 실행하고 난 후 컨테이너를 식별할 수 있는 고유한 ID를 출력한다.
컨테이너 ID는 docker ps로 확인할 수 있다.
--name 옵션으로 이름을 설정하지 않으면 문자열을 임의로 생성하여 부여한다.

💡 note
컨테이너는 변경 불가능한 인프라(immutable infrastructure)를 지향한다.
초기에 인프라를 구성한 후 임의로 디렉터리 연결이나 포트 노출과 같은 설정을 변경할 수 없다.
이러한 특성 덕분에 컨테이너로 배포된 인프라는 배포된 상태를 유지한다.

docker ps

docker ps
docker ps -f id=e5  //id의 일부로 필터링하여 검색할 수 있다. 
docker ps -a  //중지된 컨테이너까지 조회

컨테이너 정지 및 삭제하기
docker stop a15 e52 //컨테이너 실행 중지
docker container prune //중지된 컨테이너 모두 삭제, 이미지 삭제가 아님
docker image prune -a //모든 도커 이미지 삭제 (연관된 컨테이너가 없는 경우 삭제)

이미지를 사용하고 있는 컨테이너가 있는 경우 WARNING! This will remove all images without at least one container associated to them. 이라는 메시지가 뜬다.
→ docker prune 을 이용하여 컨테이너를 지우고 이미지를 지워야 한다.


도커 컨테이너 데이터 관리

도커 컨테이너에 사용된 파일들은 컨테이너가 삭제될 때 함께 삭제된다. 도커에서 많은 애플리케이션을 저장해서 계속적으로 사용할 수 있도록 해주는 옵션이 바로 볼륨과 바인드 마운트(bind mount)이다.

  • 바인트 마운트
    호스트의 특정 디렉터리를 직접 연결
    호스트의 파일 시스템과 컨테이너 내부를 연결해 양쪽의 내용이 동시에 반영되는 방법
  • 볼륨
    볼륨 공간(에서 디렉터리를 마운트)을 만든 후 그 볼륨 공간을 연결
    도커가 관리하는 볼륨을 컨테이너와 연결 → 공유 디렉터리에 생성

바인드 마운트
바인드 마운트로 호스트와 컨테이너를 연결하기 위해서는
연결 대상이 되는 컨테이너 내부의 디렉터리 구조를 먼저 알아야 한다.
예를 들어 nginx의 경우 수정해야 하는 파일의 경로 는 /etc/nginx/nginx.conf에 존재한다.

바인드 마운트 Nginx 컨테이너를 생성해보자
실행 환경은 동일하게 컨테이너를 rockylinux에서 진행한다.

mkdir -p /root/html

docker run -d -p 8081:80 \
-v /root/html:/usr/share/nginx/html --restart always --name nginx-bind-mounts nginx
//-p [로컬포트]:[컨테이너포트]
//-v [로컬경로]:[컨테이너경로]

docker ps -f name=nginx-bind-mounts  //컨테이너 조회

컨테이너는 포트, 이름 등이 겹치면 생성이 안 되므로 주의
바인트 마운트는 호스트 디렉터리의 내용을 그대로 컨테이너 디렉터리에 덮어쓴다는 특성이 있다.
따라서 컨테이너 디렉터리에 어떠한 내용이 있다라도 해당 내용은 삭제된다.

현재는 마인드 마운트 됐으나 해당 경로에 파일이 없는 상태이다.
로컬 경로인 /root/html 에 index.html을 생성한다.

index.html

//register sample code
<!DOCTYPE html>
<html> <head> <h1> Company Registration Form</h1> 
</head> 
<body> 
<form> 
<table> <tr> <td> Email Address: </td> <td> <input type=”text” email=””> </td> </tr> <tr> <td> Password: </td> <td> <input type=”Password” name=””> </td> </tr> </table> 
</form> 
</body> 
</html>

마스터 경로인 /root/html 와 호스트 경로인 /usr/share/nginx/html 로 바인드마운트로 index.html이 호스트에서 컨테이너로 전달된다.

http://192.168.1.10:8081/ 로 접근했을 때 업로드한 파일이 렌더링 된 화면을 볼 수 있다.

docker exec [컨테이너ID] [명령어] [경로] 컨테이너의 경로 파일 조회하기

docker exec -it [컨테이너ID] /bin/bash 컨테이너의 콘솔로 접근하는 명령어(i : interactive, t : tty pseudo)


볼륨(volume)

볼륨은 도커가 직접 관리하며 컨테이너에 제공하는 호스트의 공간이다.

docker volume create nginx-volume 볼륨 생성하기

docker volume ls 생성된 볼륨을 확인할 수 있다.

docker volume inspect nginx-volume 볼륨에 적용된 드라이버 종류와 실제 호스트에 연결된 디렉터리, 볼륨 이름 등을 조회할 수 있다.


컨테이너 내부와 연결할 때 전체 디렉터리 경로를 사용하지 않고 볼륨 이름만으로 간편하게 연결할 수 있다.

"Mountpoint": "/var/lib/docker/volumes/nginx-volume/_data" 라고 명시된 부분은 로컬에 연결된 볼륨의 위치를 말한다.

docker volume rm [볼륨 이름]
docker volume prune //연결되지 않은 도커 볼륨 삭제 가능

호스트와 컨테이너의 디렉터리를 연결할 컨테이너 구동
기존 컨테이너는 설정을 바꿀 수 없기 때문에 새로운 컨테이너 구동한다.

8082 포트 nginx 컨테이너 생성

docker run -d -v nginx_volume:/usr/share/nginx/html -p 8082:80 --restart always --name container1 nginx:latest
//-v [볼륨 이름]:[컨테이너 디렉터리]
/생성한 nginx_volume 과 컨테이너의 /usr/share/nginx/html 경로와 연결할 수 있는 볼륨인 nginx-volume을 생성한다. 
/생성한 nginx_volume 과 컨테이너의 /usr/share/nginx/html 경로와 연결할 수 있는 볼륨인 nginx-volume을 생성한다. 

8083 포트 nginx 컨테이너 생성, 단 볼륨은 앞과 똑같이 nginx_volume
docker run -d -v nginx_volume:/usr/share/nginx/html -p 8083:80 --restart always --name container nginx:latest

ls /var/lib/docker/volumes/nginx_volume/_data mount point로 지정된 로컬 디렉터리를 조회한다.

바인드 마운트와 달리 볼륨은 빈 디렉터리를 덮어 쓰지 않고 컨테이너 내부에 이는 파일을 보존하는 것을 확인할 수 있다.
양쪽 디렉터리를 서로 동기화 시키는 구조이기 때문에 비어있는 볼륨을 연결하는 경우에는 컨테이너 디렉터리에 있는 파일이 보존된다.
하지만 볼륨에 컨테이너 디렉터리와 동일한 파일이 존재한 상태로 연결하는 경우에는 덮어쓰기가 되니 이 점에 대해 유의할 필요가 있다.

docker inspect container1 컨테이너의 여러 요소에 대한 상세 정보를 보여준다.

컨테이너에는 여러개의 볼륨을 적용할 수 있는데 컨테이너에 volume을 설정하게 되면 나중에 세팅을 바꾸기가 어렵기 때문에 초기에 설정을 해야한다.

docker run -d -v volume1:/usr/share/nginx/html -v volume2:/var/lib/mysql -p 8083:80 --restart always --name iamcontainer nginx:latest

로컬에 볼륨과 관련된 디렉터리를 생성하고 컨테이너와 연결을 할 때, 볼륨은 로컬에 있는 파일을 복사해서 컨테이너에 업데이트 하는 방식이다.
그렇게 때문에 로컬의 볼륨 파일에 있는 내용과 컨테이너의 디렉터리에 있는 내용이 동기화 될 수 있다.

볼륨, 바인드 마운트 모두 컨테이너가 중지 되더라도 파일이 유지된다.
도커 컨테이너 생성 시 권장되는 방법은 volume이다.
도커 솔루션으로 관리되기 때문에 docker volume ls 로 조회할 수 있고 docker volume rm 으로 삭제할 수 있다.
볼륨을 컨테이너 끼리 공유할 수 있다.


note
또한, 사용하려는 볼륨의 경로를 설정할 때 올바른 경로로 설정하기 위해서는 이미지 내의 폴더 구조를 알아야 한다.

https://hub.docker.com/_/nginx
docker hub에는 다음과 같이 이미지의 기본 정보를 명시해준다.


사용하지 않는 컨테이너 정리하기

컨테이너나 이미지를 삭제하기 전에 먼저 컨테이너를 정지해야한다.

컨테이너 정지하기

docker ps -q -f ancestor=nginx
//-f : 컨테이너를 필터링
//-q(--quiet) : 해당되는 컨테이너의 ID만 설정한다. 
//ancestor는 컨테이너를 생성하는데 사용한 이미지를 기준으로 필터링한다.

docker stop $(docker ps -q -f ancestor=nginx) $() 내부의 명령을 변수삼아 실행하면 해당하는 모든 컨테이너를 정지된다.
docker stop $(docker ps -a -q) 모든 컨테이너를 정지시킨다.

컨테이너 삭제하기
docker container prune 정지되어있는 모든 컨테이너를 완전 삭제한다.
docker rm $(docker ps -aq -f ancestor=nginx) 기존에 정지된 모든 컨테이너를 nginx로 필터링하여 삭제한다.

컨테이너 이미지 삭제하기
컨테이너의 기반 이미지를 삭제한다. → 이미지 삭제 시에도 stop, rm 까지 해주어야 함
이미지를 사용하는 컨테이너가 있을 때 이미지를 지울 수 없다.
참고로 이미지는 컨테이너가 정지 상태가 아닌 삭제 상태일 때 삭제할 수 있다.
docker rmi $(docker images -q nginx) nginx:stable, nginx:latest를 모두 삭제함
docker iamge prune -a 모든 이미지 삭제

모두 삭제되었는지 다음의 명령어로 확인해볼 수 있다.

docker images
docker ps -a
docker volume ls

참고자료
[도서]컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커
https://www.oracle.com/kr/cloud/cloud-native/container-registry/what-is-docker/

profile
꾸준하게

0개의 댓글