사전 네트워크 정보

- docker 호스트는 Virtual Box 가상머신이고, 네트워크는 내 컴퓨터 어댑터에 브릿지를 했음.

- 내 컴퓨터는 공유기 밑에서 192.168.1.X 이고, docker 호스트는 192.168.1.61 이다.

- 어댑터에 브릿지를 했으므로, docker 호스트 가상머신은 내 컴퓨터와 동일한 네트워크의 서버로 이해할 수 있다.

 

nginx 컨테이너 생성하기

nginx는 대량의 요청을 처리하는 대규모 사이트에서 주로 이용하며, 리버스 프록시나 로드밸런서와 같은 기능도 갖고 있다.

 

docker container run --name webserver -d -P nginx

- nginx의 포트를 호스트의 임의 포트에 할당하여 백그라운드로 nginx 실행. 컨테이너 이름은 webserver 이다.

- 이미지가 없으면 알아서 자동으로 받는다.

 

2. 현재 상태 확인

docker ps

- 컨테이너의 80번 포트와 호스트의 32805 포트가 연결된 것을 확인할 수 있다.

 

3. 직접 접속 테스트

 

 

node.js 컨테이너 생성하기

1. 컨테이너 생성

docker run -d -it -p 9000:8000 --name=nodejs_test2 node:latest 

- 최신 node.js 컨테이너를 생성함. 백그라운드로 생성하고 인터렉티브 쉘을 열며, 이름은 nodejs_test2 이다.

 

2. 현재 상태 확인

docker ps

- 컨테이너에서 8000번포트를 사용하고, 호스트에서는 9000번 포트를 사용하여 컨테이너의 8000번 포트와 연결

 

3. 예시파일 만들기

var http = require('http');
var content = function(req, resp) {
        resp.end("Welcome to Kubernetes~!" + "\n");
        resp.writeHead(200);
}
var w = http.createServer(content);
w.listen(8000);

- 위 내용을 vi로 호스트 서버에서 nodejs_test.js 로 생성한다.

- 이 예시는 8000번 포트를 listen 하도록 설정하였다. (컨테이너의 열린 포트가 8000이므로)

 

4. 예시파일을 컨테이너에 복사하기

docker cp nodejs_test.js nodejs_test2:/nodejs_test.js

 

5. 컨테이너에 진입 후 node.js 실행

docker exec -it nodejs_test2 /bin/bash

- 진입 후, ls 명령으로 확인하면 nodejs_test.js 가 있는것을 확인할 수 있다.

- 해당 파일 위치를 확인후, 아래와 같이 실행한다.

node nodejs_test.js

- 아래와 같이 프롬프트가 떨어지지 않고 유지된다.

 

6. 직접 접속 테스트

 

 

httpd (Apache) 컨테이너 생성하기

1. 컨테이너 생성

docker run -d -p 8080:80 --name httpd-basic httpd:2.4

- httpd를 백그라운드로, 이름은 httpd-basic, 버전은 2.4 버전으로 컨테이너를 생성한다.

 

2. 현재 상태 확인

docker ps

- 포트는 컨테이너 80번, 호스트OS는 8080번으로 포트를 연결하였음.

 

3. 직접 접속 테스트

 

 

docker container run 명령 개요

docker container run 구문은 도커에서 가장 중요하고 기능이 많아서, 따로 한 페이지로 떼어 두었다. 사실상 가장 핵심적인 내용이다. 이 run 명령어는 pull, create, start 3가지를 모두 수행한다. 그래서 이미지가 없이 run을 수행하면 이미지를 받고, 컨테이너를 생성하고, 시작도 수행한다. 시작하면서 명시한 명령도 수행한다. 

docker container(안써도됨) run [옵션] 도커이미지명[:태그] [명령어]

이 명령의 옵션은 크게 4가지로 나뉜다. 그 설정은 다음과 같다.

 

  • 컨테이너 설정 옵션

  • 네트워크 설정 옵션

  • 환경변수 설정 옵션

  • 자원제한 설정 옵션

또한 도커 서버가 아닌 도커 서버-클라이언트로 구성된 경우(즉, 서버는 따로 있고 내가 명령어 치는 곳이 클라이언트인 경, 클라이언트에서 docker run 을 수행하면, 도커 서버의 docker daemon에 의해 실행되며, 결과를 클라이언트가 받아서 볼 수 있다.

 

컨테이너 설정 옵션

attach, -a

표준입력, 표준출력, 표준오류출력에 어태치한다.

--cidfile

컨테이너 아이디를 파일로 출력한다.

--detach, -d

컨테이너를 생성하고 백그라운드에서 작동시킨다. 보통 많이 쓴다. 

--interactive, -i

컨테이너의 표준 입력을 연다.

--tty, -t

단말기 디바이스를 사용한다.

--name

컨테이너의 이름을 만든다. 안쓰면, 랜덤으로 생성된다.

--user, -u

사용자명을 지정

--restart=[옵션]

명령의 실행 결과에 따라 재시작을 하는 옵션

no : 재시작하지 않음

on-failure : 종료 스테이터스가 0이 아닐 때 재시작한다.

on-failure:횟수n : 종료 스테이터스가 0이 아닐 때 n번 재시작한다.

always : 항상 재시작한다. (exit로 나가도, 재시작한다)

unless-stopped : 최근 컨테이너가 정지 상태가 아니라면 항상 재시작한다.

--rm

명령 실행 완료 후에 컨테이너를 자동 삭제 (--restart 옵션과 함께 사용할 수 없음)

 

# 참고 : 컨테이너의 "종료"
대부분의 컨테이너는 명령어에 /bin/bash를 넣으면, 해당 컨테이너에 진입할 수 있다. 컨테이너 진입한 후, exit를 입력하면 쉘에서 나가는게 아니고, 컨테이너를 "종료" 한다. 컨테이너에 인수를 넣으면, 그 인수를 "가진" 컨테이너로써 생성된다. 원래 컨테이너는 인수 없이 컨테이너에 구축된 내용 그대로 사용한다. 하지만 필요한 경우와 여러가지 사용을 위해 인수(명령어)를 추가하여 컨테이너를 실행한다. 컨테이너를 종료하지 않으려면, ctrl+p+q를 입력하여 빠져나올 수 있다.

 

docker container run centos

아무 일도 없이 컨테이너가 종료된다. 받은 인수가 없어 할 일이 없기 때문이다.

 

docker container run -itd centos

컨테이너가 백그라운드로 작동하고, 표준 입력 터미널이 열린 상태가 된다. 컨테이너가 계속 유지된다.

 

docker container run centos /bin/cal

아래와 같이 결과가 나오며 컨테이너가 종료된다. 받은 인수의 결과를 리턴하고 더이상 할 일이 없기 때문이다.

 

docker container run -itd centos /bin/cal

아무 결과도 없이 컨테이너가 종료된다. 백그라운드에서 /bin/cal을 실행하고 종료되었기 때문이다.

 

docker container run -it centos /bin/ping localhost

컨테이너로 진입 후 계속 핑을 날리게 된다. 끝없이.

ctrl+p+q로 빠져 나가면 이것은 백그라운드로 계속 ping을 날리는 중이다. 컨테이너는 살아있다.

만약 ctrl+p+q로 빠져 나가지 않고 exit로 나갔다면, 해당 명령이 끝나므로 컨테이너는 종료된다. 

 

 

네트워크 설정 옵션

포트 번호같은 네트워크 설정을 통해 외부에서 컨테이너의 프로세스에 액세스하도록 설정할 수 있고, 컨테이너끼리 통신도 할 수 있는 여러가지 네트워크 통신을 설정할 수 있다.

--add-host=[호스트명:ip주소]

컨테이너의 /etc/hosts 에 호스트명과 ip 정의

--dns=[ip주소]

컨테이너용 dns서버의 ip주소 지정

--expose

지정된 범위의 포트 번호를 할당
호스트OS까지만 해당 컨테이너의 포트를 노출한다. (외부에는 노출하지 않음)
expose한 포트는 호스트에서만 연결이 된다.
호스트에서만 쓸 목적으로 사용하는것이며 서비스로는 사용하지 않는다.

--mac-address=[맥주소]

컨테이너의 맥주소 지정

--net=[bridge | none | container:<이름 | id> | host | NETWORK]

컨테이너의 네트워크를 지정. 도커에서는 기본적으로 호스트os와 브릿지 연결을 하며, --net옵션을 통해 네트워크 설정 가능

- bridge : 브리지연결 사용 (default)

- none : 네트워크 연결하지 않음

- container:[이름 | id] 다른 컨테이너의 네트워크를 사용 (해당 컨테이너의 네트워크 기법을 그대로 사용하겠다는 의미.)

- host : 컨테이너가 호스트 os의 네트워크를 사용

- NETWORK : 사용자 정의 네트워크를 사용

--hostname, -h

컨테이너 자신의 호스트명을 지정

--publish, -p [호스트의포트번호]:[컨테이너포트번호]

호스트포트와 컨테이너포트를 매핑. 명시한 포트에 대한 액세스를 허가하기 위해 사용된다.
(-p 80:80 이라고 하면, 80번 포트에 대한 액세스를 허가)
호스트os를 넘어 외부에 포트를 오픈한다.

둘이 되도록이면 같은 포트는 피해야 한다. -p 1521:1523 이런식으로.
-p  80 이렇게 하나만 있으면 컨테이너의 포트이다. 호스트포트는 알아서 지정하라는뜻.

docker ps에서 의미 예시
 -p 8080:80 옵션으로 하면 다음과 같이 docker ps에서 확인할 수 있다.
0.0.0.0:8080->80/tcp
 : 컨테이너 80/tcp가 호스트 0.0.0.0:8080에 연결된 것. 
즉, 외부에서 도커 호스트의 8080 포트로 요청이 들어오면, 컨테이너의 80번 포트로 해당 요청을 forword.
--publish-all, -P 호스트의 임의의 포트를 컨테이너에 할당. 호스트os를 넘어 외부에 포트를 오픈한다.
알아서 32767번부터 포트를 임의로 넣어준다. 아무옵션없이 대문자P 로 옵션을 넣기만 하면 됨

 

예시 : 포트 설정

docker container run -d -p 8080:80 nginx

- nginx라는 이미지를 바탕으로 컨테이너를 생성하고, 백그라운드에서 실행한다. 그리고 호스트 포트 8080과 컨테이너포트 80을 매핑한다. (0.0.0.0:8080->80/tcp)

- 즉 이 명령을 실행하여 컨테이너를 만든 후, 브라우저 등에서 호스트의 8080에 엑세스하면 컨테이너에서 작동하고 있는 nginx(80번포트) 서비스에 엑세스할수 있다.

 

예시 : dns 서버 설정

docker container run -d --dns 192.168.1.1 nginx

 

예시 : 맥주소 설정

docker container run -d --mac-address="92:d0:c6:0a:29:33" centos

- docker container inspect --format="{{ .Config.MacAddress }} 로 실제 설정값 확인 가능

 

 

예시 : /etc/hosts 호스트명과 ip주소 정의하기

docker container run -it --add-host test.com:192.168.1.1 centos

 

예시 : 컨테이너 호스트명 설정

docker container run -it --hostname www.test.com

- 이 값은 자신의 /etc/hosts에도 자동으로 적용된다.

 

 

예시 : 도커 네트워크 명시하여 연결

docker container run -itd --name=webap --net=web-network nginx

- nginx 이미지이고 이름이 webap인 컨테이너를 web-network라는 도커 네트워크에 연결한다.

 

 

 

서버 환경설정 옵션

해당 컨테이너 OS의 환경설정을 컨테이너 생성시 사전에 설정할 수 있다. DB나 특정 어플리케이션들은 환경변수가 필수이며, 해당 환경변수 관련해서는 Docker hub의 description을 참고해야 한다.

--env=[환경변수], -e

환경변수 설정. -e -e -e 이런식으로 여러개 나열해서 명시할 수있음.

--env-file=[파일명]

환경변수를 파일로부터 설정(양이 많을 때)

--read-only=[true | false]

컨테이너의 파일 시스템을 읽기 전용으로 만듬

--workdir=[경로], -w

컨테이너의 작업 디렉토리 (시작디렉토리) 지정. 디렉토리는 자동으로 만들어진다.

--user=[사용자명], -u

사용자명 또는 UID를 지정한다.

 

예시 : 환경변수 설정

docker container run -it -e foo=bar centos /bin/bash

컨테이너 들어간 후, set 명령을 치면 설정된 환경변수들을 확인할 수 있다.

 

예시 : 환경변수 파일로 여러개 일괄 등록하기

# cat env_list
hoge=fuga
foo=bar

docker container run -it --env-file=/test/env_list centos /bin/bash

 

예시 : 컨테이너의 작업 디렉토리를 지정하기

docker container run -it -w=/tensorflow centos /bin/bash

 

 

 

자원설정 옵션

다음 포스팅에서 상세하게 확인할 수 있다.

2020/05/15 - [Docker Basic] - [Docker Basic] 15. Docker Container 자원 제한

 

[Docker Basic] 15. Docker Container 자원 제한

도커 컨테이너에서는 여러가지 자원을 할당할 수 있는데, 할당하지 않으면 해당 컨테이너는 마음대로 호스트의 자원을 사용한다. (CPU, MEMORY, swap 등) 따라서 어플리케이션에 따라 사용하는 자원�

watch-n-learn.tistory.com

 

 

 

# 추가 개념 이해 : 도커 컨테이너가 꺼질 때도 있고 안꺼질 때도 있는데..??

도커 컨테이너를 단순히 나갈려고 했는데 컨테이너가 내려가는 경우가 많다. Production 장비에서는 매우 위험한 일이므로 docker run의 개념과 컨테이너 내부에서 exit 명령과 ctrl+p+q 를 정확히 이해해야 한다. 테스트에는 "운영체제" 컨테이너와 "프로그램" 컨테이너 2가지에 따라 실행 및 종료 옵션을 여러가지 변경하여 테스트를 해 보았다. 그냥 아무생각 없이 도커에서 아래 내용을 쭉 쳐보면서 설명을 읽어보면 컨테이너가 어떻게 작동하는지 어느정도 감을 잡을 수 있을 것이다.

 

* 운영체제 컨테이너

 

docker run ubuntu 

프롬프트 떨어짐. 컨테이너 종료됨
docker ps -a로 확인하면, COMMAND 부분이 "/bin/bash"라고 되어있음.
포그라운드에서 bash 쉘을 실행한 후, 추가로 할 것이 없으므로 종료된다.

 

docker run ubuntu /bin/bash 

 

프롬프트 떨어짐.  컨테이너 종료됨. 위와 동일하다.
docker ps -a로 확인하면, COMMAND 부분이 "/bin/bash"라고 되어있음.

포그라운드에서 bash 쉘을 실행한 후, 추가로 할 것이 없으므로 종료된다.


docker run -it ubuntu

컨테이너 프롬프트로 들어가짐.  exit 로 나가면 컨테이너 종료됨. ctrl+p+q 로 나가면 계속 살아있음
docker attach 컨테이너명 으로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료된다.

attach는 단순히 컨테이너에 붙은 것이고, 현재 컨테이너상태에 대하여 exit를 했기 때문.

컨테이너의 표준 입력 옵션이 들어있으므로 컨테이너에 진입된 상태가 유지된다.


docker run -it ubuntu /bin/bash
컨테이너 프롬프트로 들어가짐.  exit 로 나가면 컨테이너 종료됨.  ctrl+p+q 로 나가면 계속 살아있음. 위와 동일하다.
docker attach 컨테이너명 으로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료된다.

attach는 단순히 컨테이너에 붙은거고, 현재 컨테이너상태에 대하여 exit를 했기 때문.

컨테이너의 표준 입력 옵션이 들어있으므로 컨테이너에 진입된 상태가 유지된다.

 

docker run -d ubuntu
프롬프트 떨어짐. 종료됨
docker ps -a로 확인하면, COMMAND 부분이 "/bin/bash"라고 되어있음.

백그라운드에서 bash 쉘을 실행한 후, 추가로 할 것이 없으므로 종료된다.


docker run -d ubuntu /bin/bash
프롬프트 떨어짐. 종료됨
docker ps -a로 확인하면, COMMAND 부분이 "/bin/bash"라고 되어있음.
백그라운드에서 bash 쉘을 실행한 후, 추가로 할 것이 없으므로 종료된다


docker run -it -d ubuntu
프롬프트 떨어짐. 종료되지 않음. 백그라운드에서 bash 쉘이 실행되고 표준 입력이 실행된 상태이기 때문.
docker ps -a로 확인하면, COMMAND 부분이 "/bin/bash"라고 되어있음.
docker exec -it ubuntu /bin/bash로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료되지 않는다. exec로 실행한 /bin/bash가 종료되었을뿐.
docker attach 컨테이너명 으로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료된다. attach는 단순히 컨테이너에 붙은거고, 현재 컨테이너상태에 대하여 exit를 했기 때문.

 

docker run -it -d ubuntu /bin/bash
프롬프트 떨어짐. 종료되지 않음. 백그라운드에서 bash 쉘이 실행되고 표준 입력이 실행된 상태이기 때문.
docker ps -a로 확인하면, COMMAND 부분이 "/bin/bash"라고 되어있음.
docker exec -it ubuntu /bin/bash로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료되지 않는다. exec로 실행한 /bin/bash가 종료되었을뿐.
docker attach 컨테이너명 으로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료된다. attach는 단순히 컨테이너에 붙은거고, 현재 컨테이너상태에 대하여 exit를 했기 때문.

 


* 소프트웨어 컨테이너


docker run httpd:latest
이렇게 하면, 로그만 뜨고 대기함. 프롬프트도 안뜸. ctrl+c 로 나가면, 컨테이너 종료됨, docker ps -a로 확인하면, COMMAND 부분이 "http-foreground"라고 되어있음.
crtl+c 나가기 전에, 창을 하나 더 띄워서 docker ps 로 보면 살아있다.

즉 OS에 httpd를 실행시켜놓은 상태로 run 되었고, 계속 실행중이므로 프롬프트 없이 대기하는 것임.


docker run httpd:latest /bin/bash
이렇게 하면, 그냥 끝남. 프롬프트 떨어짐. /bin/bash라는 배쉬 쉘을 실행한 후, 할게 없으니 종료된다. docker ps -a로 확인하면, COMMAND 부분이 "/bin/bash"라고 되어있음.

실제로 이것은 httpd가 실행되어있는 컨테이너의 OS에서 /bin/bash를 실행한 것이다. /bin/bash를 실행하고 할 게 없으므로 종료되는 것.

 

docker run -it httpd:latest
이렇게 하면, 로그 뜨고 컨테이너 프롬프트가 뜬다. httpd가 올라가 있는 컨테이너 OS를 포그라운드로 실행했으므로.

ctrl+c로 나가면 컨테이너는 종료된다. 즉, httpd가 종료되며 컨테이너도 종료되는 것.
docker ps -a로 확인하면, COMMAND 부분이 "http-foreground"라고 되어있음.

docker run -it httpd:latest /bin/bash
이렇게 하면, 컨테이너 프롬프트가 뜬다. httpd가 올라가 있는 컨테이너 OS에 /bin/bash를 포그라운드로 실행했으므로.
exit로 나가면 컨테이너가 종료된다. 즉 컨테이너 실행시 명시한 /bin/bash가 끝났기 때문에 컨테이너 자체가 종료되는 것.
crtl+c 나가기 전에, 창을 하나 더 띄워서 docker ps 로 보면 살아있다.
이상태에서, docker exec -it 이름 /bin/bash 라고 하면 들어가짐. 들어간 후 exit 하면? 컨테이너는 살아있다. 이유는? exec로 실행한 /bin/bash 만 종료했기 때문. 최초 실행한 /bin/bash는 실행된 상태에서 아직 유지중.
docker attach 컨테이너명 으로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료된다. attach는 단순히 컨테이너에 붙은거고, 현재 컨테이너상태에 대하여 exit를 했기 때문.

docker run -d httpd:latest
이렇게 하면, 그냥 프롬프트 떨어지고, 컨테이너는 계속 살아있다.
이상태에서, docker exec -it 이름 /bin/bash 라고 하면 들어가짐. 들어간 후 exit 하면? 컨테이너는 살아있다. 이유는? exec로 실행한 /bin/bash 만 종료했기 때문.
docker attach 컨테이너명 으로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료된다. attach는 단순히 컨테이너에 붙은거고, 현재 컨테이너상태, 즉 httpd을 실행한 것에 대하여 exit를 했기 때문.

docker run -d httpd:latest /bin/bash
이렇게 하면 그냥 프롬프트 떨어지고, 컨테이너는 종료된다.
/bin/bash를 백그라운드로 실행시키고 할 게 없으니 종료된 것임.

docker run -it -d httpd:latest
이렇게 하면, 프롬프트 떨어지고 컨테이너는 계속 살아있다.
이상태에서, docker exec -it 이름 /bin/bash 라고 하면 들어가짐.

들어간 후 exit 하면? 컨테이너는 살아있다. 이유는? exec로 실행한 /bin/bash 만 종료했기 때문. 그냥 -d로 한 것과 동일하다.
docker attach 컨테이너명 으로 들어가면 바로 종료된다. -it 옵션이 인터렉티브 모드이고, 인터렉티브 상태를 attach 했는데 그 후 할 게 없으므로 종료됨. (조심해야 할 듯)

attach는 단순히 컨테이너에 붙은거고, 현재 컨테이너상태에 대하여 exit를 했기 때문.

docker run -it -d httpd:latest /bin/bash
이렇게 하면, 프롬프트 떨어지고 컨테이너는 계속 살아있다. 
이상태에서, docker exec -it 이름 /bin/bash 라고 하면 들어가짐. 위와 다른점은

들어간 후 exit 하면? 컨테이너는 살아있다. 이유는? exec로 실행한 /bin/bash 만 종료했기 때문.  그냥 -d로 한 것과 동일하다.
docker attach 컨테이너명 으로 들어간 후 exit 쳐서 나가면, 컨테이너는 종료된다. attach는 단순히 컨테이너에 붙은거고, 현재 컨테이너상태에 대하여 exit를 했기 때문.

 


결론
- 도커 컨테이너 실행시 어떤 명령어로, 어떤 옵션으로  실행시켰느냐에 따라 도커 생성의 정체성이 달라지므로, 그 정체성에 따라 exit를 쳤을때 컨테이너가 종료될수도, 종료되지 않을수도 있음.
- 도커 컨테이너가 종료되지 않을려면, 도커 컨테이너 실행시 시작한 프로그램을 종료하지 않도록 해야 한다.
- attach 명령어는 stdout, stderr을 가져오는 것이다. ssh처럼 연결되는 것이 아니다. 
-  모르면 exit로 나가지 말고, ctrl+p+q 하는게 가장 좋다.

도커 레지스트리란?

도커 이미지를 사용자들끼리 공유할 수 있도록 하는 플랫폼이다. 이러한 레지스트리는 크게 2가지 종류, Public 레지스트리, Private 레지스트리로 나뉜다.  Public 레지스트리는 도커의 공식 레지스트리인 도커 허브와 기타 다른 벤더 업체들의 레지스트리가 존재한다.  Private 레지스트리는 사용자가 직접 레지스트리를 구축해서 자신의 내부망에서 사용(팀원이나 회사에서 공유)하거나 외부망과 연결해서 사용할수도 있다. 


도커허브

도커 허브는 도커의 Official 이미지 공유 사이트이다. 도커 허브에서 이러한 이미지를 자신의 도커로 다운받을 수 있고, 자신이 만든 이미지를 올릴 수도 있다. 도커허브에서는 대부분의 오픈소스 소프트웨어와 상용 소프트웨어는 제작사들이 Official하게 자신의 소프트웨어를 이미지로 만들어 공유하고 있다. (물론 라이센스는 주의해야 한다) 예를들어 오라클 이미지는 라이센스를 구매해야 하지만, 오라클XE 버전이 있는 이미지가 있다. 이러한 이미지는 사용할 수 있다.

 

우리가 상상하는 모든 서비스는 다 도커 허브에 이미지화 되어 있다고 생각하면 편하다. 또한 도커 엔진이 올라간 운영체제와 상관없이, 모든 이미지가 서로 호환되고 컨테이너화 가능하다.

 

도커허브는 github, bitbucket같은 소스코드 관리 툴과 연계가 가능하다. 예를들어 github상에서 dockerfile(도커 이미지를 만드는 스크립트)를 관리하고, 거기서 도커 이미지를 자동으로 생성하여 도커 허브에 업로드하는 등 여러가지 방법으로 사용 가능하다.


도커허브의 이미지 변조 방지 및 취약성 검사 기능

도커허브 또는 공개 레지스트리는 아무래도 오픈되어 있으므로 변조하여 공격을 하거나 취약점을 만들어 내는 위험한 이미지가 있을수도 있다. 보통으로 사람들이 자주 사용하는 official 한 이미지를 잘못 다운받게 하여 공격하는 방식이 많이 사용된다. 이러한 위험을 막기 위해 도커 이미지를 검증 및 확인하는 기능들이 도커 허브에 포함되어 있다.

docker container trust 
도커 이미지 제공자를 검증하는 기능. 이미지 제공자는 도커 레지스트리에 이미지를 송신하기 전에, 로컬 환경에서 비밀키를 사용하여 이미지에 서명을 한다. 그 후 그 이미지를 이용할 때는 이미지 제공자의 공개키를 사용하여 실행하려고 하는 이미지가 정말 제공자가 작성한건지 확인한다. 만일 이미지가 변조된 경우 이미지를 무효로 만든다.


docer security scanning
도커 이미지를 검사하여 이미 알려진 보안상의 취약성이 없다는 것을 확인하여 이미지의 안전성을 확인한다.


도커허브 사용하기

1. 접속하기

- https://hub.docker.com/ 에 접속한다.

 

2. 계정을 만들고 로그인한다.

- 로그인이 되면 다음과 같이 자신의 화면이 나온다. 여기서 자신이 올린 이미지 정보를 확인 및 설정할 수 있다.

3. 원하는 어플리케이션의 이미지를 검색한다.

- 화면 상단 돋보기로 원하는 이미지를 검색할 수 있다.

- 검색된 이미지에서 official image는 이전에 언급한대로 해당 어플리케이션 제조사가 공식적으로 만든 이미지이다.

- 보통 이러한 공식 이미지를 바탕으로 자신의 설정에 맞게 변경하여 사용하게 된다.

- Stars 는 SNS의 좋아요 랑 비슷하다고 생각하면 되며, 일반적으로 Stars가 많으면 신뢰도가 높다.

4. 해당 이미지의 상세사항을 살펴본다.

- 영어를 몰라도, 천천히 읽어보면 어느정도 이해할 수 있다.

- mariadb가 무엇인지 개요, 실행하는 법, 다른 어플리케이션과 연결하는 법, 라이센스, 주의사항, 메뉴얼 등 유용한 자료들이 포함되어 있다.

- 이러한 어플리케이션을 모르는 상태에서는 메뉴얼 등 자료들을 봐도 아무런 의미가 없고 이해도 못할 것이다. 따라서 도커를 제대로 배우기 위해서는 어플리케이션도 잘 알아야 한다.

- 도커허브에 있는 이미지는 "이미지명:태그" 의 형식을 취한다.

- 오른쪽에 검은바탕의 글자로 docker pull mariadb 라는 cli명령으로 도커가 설치된 호스트에서 이미지를 다운받을 수 있다. 여기서는 태그를 넣지 않았는데, 태그를 넣지 않으면 latest 태그를 사용한다.

# 태그란?

- 태그는 이미지의 버전, 속성 등을 의미한다.

- 태그 탭을 들어가면, latest, bionic, beta, 10.5.1등이 있다.

- latest는 항상 그 시점의 최신 버전을 의미하며, 10.5.1 등은 특정 버전을 의미한다.

- 즉, 버전 별 이미지를 받아 각기 다른 버전의 동일한 프로그램을 각각 동시에 띄울수도 있다.

- 태그 지정하여 명령어를 입력하는 경우, docker pull mariadb:latest 이렇게 : 이 붙은 형식으로 입력한다.

 

5. 해당 이미지의 환경변수 값을 찾아본다.

- 해당 이미지를 사용하기 위해서는 정확한 환경변수를 사용할 줄 알아야 한다.

- 이러한 환경변수는 다른 블로그나 구글링보다는 offcial한 도커 허브에서 찾는것이 가장 정확하고 신뢰도가 높다.

- 대부분의 도커 이미지는 이러한 환경변수를 가지고 있고 이미지를 컨테이너화 (실행) 하기 전에 이러한 환경변수를 원하는 세팅에 맞게 입력해주어야 한다.

- 아래 환경변수는 도커 이미지로 실행할 mysql의 유저정보, 비밀번호 정보, 데이터베이스 명 등을 변수로서 설정하는 방법을 알려준다.

이렇게 도커 허브를 통해 이미지 다운로드 및 개요, 설정정보 등을 확인할 수 있다. 이후 도커 엔진이 설치된 호스트의 cli 화면에서 도커 허브에 로그인을 한 후 이미지 다운 및 업로드가 가능하다. (즉, 도커허브를 쓰려면 호스트가 인터넷에 연결되어야 한다)

도커 이미지란?

도커는 대부분의 소프트웨어를 "이미지" 라는 개념으로 만들 수 있다. "이미지"란, 어플리케이션 실행에 필요한 프로그램 본체+라이브러리+관련 미들웨어(필요한경우)+OS/네트워크 설정값 등을 모아서 하나의 객체로 만든 것이다.  파일시스템적으로 "이미지"는, 애플리케이션의 실행에 필요한 파일들이 저장된 디렉토리를 모은 것이다.

 

도커에서 이러한 이미지를 기반으로, 실행환경에서 움직이는 컨테이너를 만들게 된다. 하나의 이미지에 여러 어플리케이션을 합칠 수도 있지만, 도커의 기본 이념은 "한 컨테이너에 한 어플리케이션" 이다.

 

단순히 운영체제(CentOS, Ubuntu) 의 이미지가 있을수도 있고, mysql이나 apache 이미지가 있을수도 있고, wordpress 같은 이미지가 있을수도 있다.  이미지는 미들웨어, 운영체제, 3rd 소프트웨어, 상용 소프트웨어, 오픈소스 소프트웨어 모두 다 존재한다.


이미지 실행 : "컨테이너화"

이미지를 도커에서 실행하면, 그 이미지를 기반으로 컨테이너가 생성되고 가동된다.  이미지는 컨테이너의 베이스일 뿐이라 한 이미지로 여러 개의 컨테이너를 만들 수 있다. 실행된 컨테이너를 가지고 서비스를 띄우고 운영하는 것이다. 예를 들어, mysql 이미지와 httpd 이미지를 다운받은 후, mysql 이미지와 httpd 이미지를 각각 컨테이너로 만들어서 서로 연동하여 웹서비스를 만들 수 있다.

 

다른 가상화 기술로 서버 기능을 실행시키려면, os의 실행부터 시작하므로 느릴 수 밖에 없지만, 도커는 이미 움직이고 있는 os 상에서 프로세스를 실행시키는것과 거의 똑같은 속도로 빠르게 실행 가능하다.


생성된 컨테이너의 개념

컨테이너는 OS 파일시스템이 있지만 커널이 없다. 호스트OS(도커가 설치된 장비)의 커널을 공유한다. 따라서 가상머신보다 훨씬 가볍다. 이 컨테이너에는 프로세스가 있으며, 해당 프로세스는 컨테이너 내에 "격리되어 있다" 라고 표현된다. 즉 호스트OS와는 분리되어 있다는 것.


컨테이너 안에서 작동하는 프로세스를 하나의 그룹으로 관리하고, 그룹마다 각각 파일시스템이나 호스트명, 네트워크 등을 할당하고 있다. 그룹이 다르면 프로세스나 파일에 대한 액세스를 할 수 없다. 이러한 구조를 사용하여 컨테이너를 독립된 공간으로서 관리하고 있다. 이를 위해 linux 커널 기능인 namespace, cgroups 등의 기술이 사용된다.


호스트OS 입장에서는 컨테이너는 프로세스로 보이며, ps 명령으로 확인할 수 있다. 컨테이너는 호스트OS와 통신을 하며, 그 통신은 네트워크로 이루어진다.  단순하게 그룹으로 관리되는 것이므로, 컨테이너와 호스트OS는 별개가 아니다. 컨테이너 내부와 호스트OS에서 둘다 uname -r을 치면, 호스트와 동일한 커널이 나온다. 호스트와 컨테이너의 OS 종류,버전은 상관없다.

# 참고 : 호스트OS=Redhat / 컨테이너=Ubuntu 버전 비교
root@457b2eb299ee:/# cat /etc/lsb-release (컨테이너457b2eb299ee의 운영체제 정보 확인)
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.3 LTS"
root@457b2eb299ee:/# uname -r (컨테이너457b2eb299ee의 커널버전 확인)
3.10.0-957.el7.x86_64
[root@CENTOS7-docker ~]# cat /etc/redhat-release (호스트OS의 운영체제 정보 확인)
CentOS Linux release 7.6.1810 (Core)
[root@CENTOS7-docker~]# uname -r (호스트OS의 커널버전 확인)
3.10.0-957.el7.x86_64 (동일하다)


도커의 이미지 데이터 저장/관리 방식 : CoW (Copy on Write)

데이터를 복사할 때 새로운 빈 영역을 확보하고 거기에 복사하는 것이 일반적인 방식이지만, 복사될 데이터에 변경이 없다면 굳이 복사를 해서 용량을 낭비할 필요가 없다. 그래서 복사를 요구받아도 바로 복사하지 않고, 원래 데이터를 그대로 참조시키고, 원본 또는 사본에 수정이 가해진 시점에 비로소 새로운 빈 영역을 확보하고 데이터를 복사하는 방식이 있다.

 

이것을 Copy on Write 방식이라고 하며, 도커에서는 이 방식을 사용하여 이미지를 저장하고 관리한다. 이미지의 여러 부분을 분할된 "레이어"를 합쳐 하나의 이미지로 만드는 개념이다. 예를 들어 apache 이미지는 아래 그림과 같이 여러개의 레이어로 이루어져 있다.

예시처럼, 이미지는 apache를 실행할 운영체제 이미지 레이어, 운영체제 업데이트 레이어, 아파치 프로그램 레이어, custom file 부분엔 아파치 값 설정이 레이어가 될 수도 있고, 또 추가적으로 레이어를 올릴 수도 있다. 그리고 마지막 부분은 read/write가 가능한 레이어로 마운트하여 사용자가 추가/수정을 할 수 있도록 하는 것이다. 각각의 이미지 레이어는 51136EA3C5A 같은 코드로 관리된다.

 

즉, 도커 이미지는 여러개의 레이어가 겹쳐저 있고, 구성 변경이 있으면 변경이 있는 부분도 레이어로 만들어서 관리하게 된다. 이 방법은 매우 혁신적이며 2가지 큰 장점을 가지고 있다. 

 

공간 활용.하나의 이미지 레이어를 여러 이미지에 사용할 수 있다. 즉, 우분투 베이스 이미지 레이어 부분을 위 예시의 apache가 아닌 elastic search 라는 프로그램 이미지에서도 우분투 베이스 이미지를 쓸 수 있으므로  한 이미지 레이어가 여러 이미지에 적용되는 것이다. 따라서 이미지의 사본을 만들지 않아 공간을 아주 많이 절약할 수 있다.

 

속도 향상 및 효과적인 자원 사용. 도커 이미지를 만들(build) 때,  raw 데이터를 가지고 빌드하는 게 아니라, 빌드할 내용 중 원래 만들어 놓은 이미지 레이어가 있다면 빌드하지 않고 그 레이어를 가져다 쓰므로 속도도 빠르고 자원도 사용하지 않는다.

 

이러한 방식을 쓰는 파일시스템을 Union Filesystem 이라고 하며, 여러가지 파일시스템 종류가 있다. AUFS, OverlayFS, loop-lvm, direct-lvm, zfs 등이 있다.

가상머신 VS 컨테이너

우리가 기본적으로 아는 가상머신은, 하나의 호스트OS 위에 가상머신 (가상 하드웨어) 를 만들고, 거기에 운영체제를 설치하고 사용하는 것이다. 즉 각 가상머신머다 커널이 다르다.

가상머신 방식

컨테이너 기술은, 가상머신과 다르게 따로 가상 하드웨어를 만들지 않는다. (따라서 BIOS에서 설정하는 CPU 가상화 설정도 필요 없다!) 아래와 같이 하나의 호스트OS 위에 컨테이너 엔진을 설치하고, 그 위에 컨테이너를 만드는 것이다.

 

간단하게 말하면 호스트OS(물리적 서버) 위에 논리적인 구획(컨테이너) 를 만들고 어플리케이션을 작동하기 위해 필요한 라이브러리나 애플리케이션을 하나로 모아 컨테이너 안에 집어넣어 마치 컨테이너 하나가 별도의 서버인 것처럼 사용할 수 있게 하는 것이다. 

 

여기서 컨테이너는, 마치 가상머신처럼 운영체제도 있는것처럼 보이고, 원하는 프로그램도 깔려있고, IP도 있다. 가상머신으로 착각할 만 하다. 하나의 호스트OS에 여러개의 컨테이너를 올릴 수 있고, 해당 호스트OS의 자원을 나눠서 사용하게 된다. 즉 컨테이너 자체에는 OS가 없고, 호스트OS의 커널을 컨테이너가 공유받는다.

컨테이너 방식

가상머신과 컨테이너는 사용자가 봤을 때 기능상으로는 비슷하지만, 각 기술들은 서로 지향하는 바가 다르다.

- 컨테이너 기술은 애플리케이션의 실행환경을 모아서 이식성을 높이고 확장성이 좋은 환경에서 작동하는것을 지향한다.
- 가상화 기술은 서로 다른 환경을 어떻게 효율적으로 에뮬레이트할지를 지향한다.

 

각 기술마다 장단점이 있고 사용하는 적절한 용도가 있지만, 단순히 성능적으로 봤을 때는 가상화보다 컨테이너가 overhead(어떤 처리를 위해 추가되는 간접적인 처리시간) 가 적어 가볍고 고속으로 작동한다.


그래서, 도커란 무엇인가?

도커는 애플리케이션 실행에 필요한 환경을 이미지로써 만들어 모아두고, 이미지를 사용하여 다양한 환경에서 애플리케이션 실행환경을 구축/운용하는 컨테이너를 만들어 사용하는 오픈소스 플랫폼이다. 2013년 3월 오픈소스 프로젝트로 시작되었고 어떤제품보다도 파급력이 컸다.

 

컨테이너는 생각보다 오래된 기술이다. FreeBSD 라는 오픈소스 유닉스의 FreeBSD JAIL, 선마이크로시스템즈(현 오라클 합병됨)의 상용 유닉스 Solaris의 Containers (Zone), 그리고 리눅스에서는 리눅스 컨테이너 (Linux Container ; LXC) 라는 기술로써 컨테이너 기술이 있었다. 또한 구글은 직접 컨테이너 기술을 만들어 사용했다. (lmctfy ; Let Me Contain That For You)

 

도커는 리눅스 커널에 포함된 LXC 기능을 사용하여 컨테이너 기술을 사용한다. LXC가 제대로 사용되지 못한 이유는 사용 및 배우는 것이 복잡하고 어려웠기 때문. (LXC의 cgroups와 namespace 등이 사용하기 쉽지 않았다.) 도커를 통해 애플리케이션이 LXC를 사용하고, 사용자는 쉬운 도커 명령어를 사용하여 컨테이너 기술을 쓸 수 있도록 했다.


도커의 장점

1. 빠르고 편한 어플리케이션 설치
- 우분투는 apt-get을 사용하고, 레드햇은 yum install 을 사용하는 등 os 별로 설치 명령이 모두 다르다.
- 도커는 항상 동일한 명령을 사용하며 훨씬 빠르다.

2. 관리의 용이함
- 사내 문서 등으로 서버 변동 내역을 기록하는 것은 시간과 인력을 많이 사용하는 일이다.
- 도커는 이러한 기록을 코드화하여 일원화하므로 따로 관리를 할 필요가 없다.
- 또한 버전별로 컨테이너를 만들수 있으므로 버전관리 및 호환성 유지가 용이하다.
- 담당자가 세팅한 설정을 스크립트화 하여 자동화할 수 있다.

3. 효율적이며 자유로움
- 동일한 컨테이너 여러대를 한번에 배포할 수 있다.
- 필요한 프로그램들을 도커허브에서 이미지의 형태로 제공받을 수 있다. (github과 유사한 방식, open share)
- 해당 이미지를 받고 내가 원하는대로 수정 및 설정하여 다시 또 배포할 수 있다.

- 서버의 견고함을 보장하면서도 동적으로 바꿀 수 있는 유연함을 가진다.

- 수평적 확장(Scale out) 이 자유롭다.

 

# 참고 : Scale out과 Scale up

4. 여러가지 변경점이나 예외사항들을 배제하기 쉬움
- 도커는 통일된 환경에서 동일한 이미지를 가지고 어플리케이션을 가동한다.
- 따라서 몇년동안 운영한 동일한 서비스를 중간에 더 추가하거나, 다른 하드웨어끼리의 차이 등에 있어서 생기는 문제 자체가 발생하지 않는다.

5. 높은 이식성
- 환경에 상관없이 컨테이너를 통해 애플리케이션을 동일한 환경에서 가동 가능.
- 온프레미스<->클라우드, 클라우드<->클라우드 등의 마이그레이션을 쉽고 빠르게 수행할 수 있다. 예를들어, 어떤 퍼블릭 클라우드 서비스의 비용이 저렴해지면 그쪽으로 쉽게 넘어갈 수 있다.

6. 개발 환경에 최적화된 기능
- 환경에 따른 차이가 없어 개발,테스트,서비스 환경을 신경쓰지 않고 프로젝트 관리가 가능하다.
- 개발을 위한 인프라 환경설정, OS 환경설정, 미들웨어, 라이브러리 설정 등을 빠르고 편하게 할 수 있다.


도커 사용을 위한 버전과 플랫폼

* 도커 CE가 지원하는 플랫폼
- 서버OS용 : 우분투, 데비안, CentOS, 페도라, 레드햇 등
- 퍼블릭클라우드용 : azure, AWS
- 클라이언트OS용 : 윈10, 맥OS 

- 기타 : Synology NAS 등

 

# 참고 : x86이 아닌 다른 아키텍쳐에서 사용

IOT 디바이스같은 arm 아키텍쳐에서 작동하는 디바이스에서는 Docker Community Edition (ARM)을 사용할 수 있다. 우분투와 데비안을 지원한다. https://docs.docker.com/install 참고할 것.

* 도커 에디션

- 무료버전 (CE) : Community Edition이다. 로컬사용 및 상용 지원이 불필요한 환경에서 애플리케이션을 실행할 때 적합하다.
- 유료버전 (EE) : Enterprise Edition 이다.  상용 이용에 적합한 버전. EE는 BASIC, STANDARD, ADVANCED 3종류가 있다.
    - BASIC : 도커사의 지원 및 도커 스토어에서 인증이 끝난 컨테이너, 인증이 완료된 플러그인을 제공한다.
    - STANDARD : 베이직 내용에 더해, LDAP, Active Directory와 통합 가능한 도커 데이터센터를 이용할 수 있음.
    - ADVANCED : 보안 기능을 추가로 제공한다.

* 도커의 Release history

https://www.docker.com/blog/docker-enterprise-edition/

- 에디션에 따라 정기적으로 릴리즈가 있다.
- 버전 번호는 연도2자리, 월2자리로 나타난다. 2017년 3월에 릴리즈된 버전은 17.03이 된다.
- 도커CE는 매월 보안 지원과 버그 수정 지원인 EDGE의 릴리즈, 4분기별로 안정판인 STABLE이 릴리즈된다.
- 도커EE도 CE의 STABLE과 똑같은 시기에 릴리즈된다.


도커의 구성요소

도커는 다음과 같은 컴포넌트로 구성되어 있고, 이러한 컴포턴트들이 조합하여 어플리케이션 실행 환경을 구축한다. 


* Docker engine
- 도커의 핵심 기능. 도커 이미지를 생성, 컨테이너를 기동한다.
- docker 명령과 dockerfile 이미지 생성도 수행한다.

* Docker Registry (이미지 공개 및 공유)
- 컨테이너의 바탕이 되는 도커 이미지를 공개 및 공유하기 위한 레지스트리 기능
- 도커의 공식 레지스트리인 도커허브도 이 Docker registry를 사용한다.

* Docker Compose (여러 컨테이너 통합 관리)
여러 개의 컨테이너 구성 정보를 코드로 정의하고, 명령을 실행함으로써 애플리케이션의 실행환경을 구성하는 컨테이너들을 일원관리하는 툴

* Docker Machine ( 도커 실행 환경 구축)
- 로컬 호스트용인 버추얼박스등을 비롯하여 AWS EC2나 MS AZURE와 같은 클라우드 환경에 Docker 실행 환경을 명령으로 자동 생성하기 위한 툴.

* Docker Swarm (클러스터 관리)
- 여러 도커 호스트를 클러스터화하는 툴
- 클러스터를관리하거나 api를 제공하는 역할은 Manager 가 수행하며, 도커 컨테이너를 실행하는 역할은 node가 담당한다.
- 쿠버네티스와 비슷하지만, 쿠버네티스는 복잡하고 명령어도 많음. 간단하게 사용할 때는 Docker Swarm을 사용할 수 있다.

 

 

 

 

 

 

 

 

 

 

+ Recent posts