이전 포스트에서는 docker host로 사용될 서버를 구성하고, docker 프로세스를 설치 및 실행해보았습니다. 이번 포스트를 통해 docker host서버 위에 새로운 우분투 컨테이너를 생성하고 ssh를 이용해 접속하는 방법을 알아보도록 하겠습니다.
docker container는 사전에 빌드 된 image 정보를 바탕으로 생성됩니다. 사용 가능한 image들은 docker hub를 통하여 저장되고 공유됩니다. 프로그래머는 자신이 빌드한 image를 모두가 사용할 수 있도록 docker hub에 공유할 수도 있고 특정 사용자만 이용할 수 있는 private 한 저장소를 구축하며 공유할 수 있습니다.
docker hub에 접속하여 사용할 수 있는 ubuntu image를 검색해봅시다.
https://hub.docker.com/_/ubuntu
등록되어있는 우분투의 버전이 위와 같이 명시되어있습니다. 그럼 ubuntu 이미지를 다운로드(pull)해보겠습니다. 그 전에 현재 docker host에서 사용 가능한 이미지의 목록을 조회하기위해 docker images
명령어를 사용해보겠습니다.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
$
현재 다운받은 이미지가 존재하지 않는 것을 볼 수 있습니다.
이제 ubuntu 22.04 이미지를 다운로드 해보겠습니다.
docker pull 명령어는 docker hub에 업로드되어있는 이미지를 현재 docker host로 가져옵니다. docker pull {image}:{version}
과 같이 사용할 수 있습니다. version을 명시하지 않을 경우 자동으로 latest 버전의 이미지가 다운로드 됩니다.
$ docker pull ubuntu:22.04
22.04: Pulling from library/ubuntu
6414378b6477: Pull complete
Digest: sha256:58b87898e82351c6cf9cf5b9f3c20257bb9e2dcf33af051e12ce532d7f94e3fe
Status: Downloaded newer image for ubuntu:22.04
docker.io/library/ubuntu:22.04
## version을 명시하지 않았을 경우
$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
dafa2b0c44d2: Pull complete
Digest: sha256:dfc10878be8d8fc9c61cbff33166cb1d1fe44391539243703c72766894fa834a
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
가져온 image가 잘 저장되어있는지 확인해보겠습니다.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest b1e9cef3f297 4 weeks ago 78.1MB
ubuntu 22.04 97271d29cb79 2 weeks ago 77.9MB
image가 정상적으로 받아졌다면 image를 사용하여 container를 생성해야합니다. docker ps
명령어는 현재 구동중인 container의 목록을 출력합니다.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
구동중인 container가 존재하지 않기 때문에 아무 목록도 출력되지않습니다. -a 옵션과 함께 다시 한번 출력해보겠습니다.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e39c9c5d19c4 ubuntu-image:1.0 "/bin/sh -c 'service…" 7 days ago Exited 1 days ago container-ubuntu
-a 옵션은 container의 실행 유무와 상관 없이 현재 host에 존재하는 모든 container를 조회하는 옵션입니다.
앞서 다운로드한 우분투 이미지(ubuntu:22.04)로 컨테이너를 생성해보겠습니다. 컨테이너 생성을 위한 명령어는 docker run <옵션> <이미지> <명령> <매개 변수>
과 같이 사용합니다. 우선은 아무 옵션도 주지 않고 실행시킬 이미지만 명시해보겠습니다.
$ docker run ubuntu:22.04
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
030098545b05 ubuntu:22.04 "/bin/bash" 4 seconds ago Exited (0) 3 seconds ago charming_shannon
의도한대로 컨테이너가 생성되었지만 STATUS를 확인해보니 컨테이너가 실행되지 않고 종료되었음을 확인할 수 있습니다. docker container는 별도 옵션 없이 실행하면 모든 표준 입력이 종료되면 컨테이너 또한 종료됩니다.
컨테이너의 구동 상태를 유지하기 위해서는 run 명령어와 함께 옵션을 지정해주어야합니다.
run 명령어 옵션들 중 자주 사용되는 명령어를 살펴보겠습니다.
--name: 실행될 컨테이너의 이름을 지정합니다. 컨테이너를 특정하여 작업이 필요할 경우 지정된 name을 활용할 수 있습니다. (생략 시 임의 name 지정)
-i(또는 --interactive): 컨테이너의 표준 입력을 활성화합니다. 컨테이너와 연결되지 않은 상태에서도 활성화된 표준 입력을 유지합니다.
-t(또는 --tty): 가상 터미널(tty)을 할당하여 사용자의 표준 입력을 컨테이너로 전달합니다.
-d(또는 --detach): 컨테이너를 백그라운드에서 실행합니다.
-p(또는 --publish): 호스트 PC와 컨테이너 간 포트 포워딩 설정이 필요할 경우
-p <호스트포트>:<컨테이너포트>
와 같이 지정합니다.
-v(또는 --volume): 호스트 PC와 컨테이너 간 연결될 디렉토리(마운팅)를 설정합니다.
-e(또는 --env): 컨테이너 내에서 사용될 환경 변수를 지정합니다.
생성된 컨테이너가 구동 상태를 유지하고 Bash를 사용하여 명령어 입력이 필요할 경우
## 구동 상태 유지, 생성된 컨테이너 이름을 'container-ubuntu'로 지정
$ docker run -itd --name container-ubuntu ubuntu:22.04
## 구동중인 컨테이너 확인
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e39c9c5d19c4 ubuntu-image:1.0 "/bin/sh -c 'service…" 4 seconds ago Up 3 seconds ago container-ubuntu
위와 같이 실행된 컨테이너가 구동상태를 유지하고 있는 것을 확인할 수 있습니다.
실행중인 컨테이너에서 실행할 명령어를 전달하고 싶을 때 docker exec를 사용합니다.
exec는 docker exec {container name} {실행할 명령어}
와 같이 사용할 수 있습니다.
앞서 실행한 컨테이너에서 간단한 echo 명령어를 실행해보겠습니다.
$ docker exec container-ubuntu echo "hello"
hello
$
exec로 실행한 echo 명령어가 실행되었습니다. 위와같이 단발성 명령어를 실행할 때는 별도 옵션 없이 exec만으로 명령어를 실행할 수 있습니다.
하지만 직접 컨테이너에 접속하여 여러가지 작업이 필요할 경우 -it
옵션을 추가하고 컨테이너 내의 bash를 실행해주면 됩니다.
$ docker exec -it container-ubuntu /bin/bash
root@e39c9c5d19c4:/#
-it
옵션을 추가하고 bash를 실행하니 컨테이너의 bash 쉘이 실행되었습니다.
클라이언트가 도커 호스트 PC에게 80포트로 요청을 보내면 실행되고있는 컨테이너 중 Nginx가 구동중인 컨테이너로 요청을 포워딩해보는 간단한 실습을 진행해보겠습니다.
이전에 다운로드 받은 ubuntu:22.04이미지를 활용하여 컨테이너를 생성하겠습니다. 다만 이번에는 호스트 PC의 80번 포트로의 요청을 생성된 컨테이너의 80번 포트로 포워딩해주는 옵션을 추가해보겠습니다.
$ docker run -itd -p 80:80 --name ubuntu-nginx ubuntu:22.04
f390de72ac1dcd57b27ca7c0c2a19601c78b58ae4e1d32a90d591d144e58c6dc
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f390de72ac1d ubuntu:22.04 "/bin/bash" 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp ubuntu-nginx
80:80 포트포워딩 설정이 완료된 우분투 컨테이너가 동작하고있는 것을 확인할 수 있습니다. 컨테이너에 접속하여 nginx 설치를 진행해보도록 하겠습니다.
$ docker exec -it ubuntu-nginx /bin/bash
root@f390de72ac1d:/# apt update
Get:1 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB]
Get:2 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
Get:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
......
root@f390de72ac1d:/# apt-get install -y nginx
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
fontconfig-config fonts-dejavu-core iproute2 libatm1 libbpf0 libbrotli1 libbsd0 libcap2-bin libdeflate0 libelf1 libexpat1 libfontconfig1 libfreetype6 libgd3 libicu70 libjbig0 libjpeg-turbo8 libjpeg8 libmaxminddb0 libmd0 libmnl0
libnginx-mod-http-geoip2 libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream libnginx-mod-stream-geoip2 libpam-cap libpng16-16 libtiff5 libwebp7 libx11-6 libx11-data libxau6 libxcb1
libxdmcp6 libxml2 libxpm4 libxslt1.1 libxtables12 nginx-common nginx-core ucf
......
Setting up nginx (1.18.0-6ubuntu14.5) ...
Processing triggers for libc-bin (2.35-0ubuntu3.8) ...
root@f390de72ac1d:/# service nginx status
* nginx is not running
root@f390de72ac1d:/# service nginx start
* Starting nginx nginx
root@f390de72ac1d:/# service nginx status
* nginx is running
root@f390de72ac1d:/# exit
$
우분투 컨테이너에 nginx가 설치되었고 프로세스가 실행중임을 확인하였습니다.
이제 크롬을 통해 호스트PC의 80포트로 요청을 보내고 nginx의 인덱스 페이지가 노출되는것을 확인해봅시다.
기본적인 docker 사용 방법을 알아보고 간단한 실습을 진행하였습니다. docker에서는 컨테이너 당 하나의 프로세스만을 구동하도록 권장하고있습니다. (예: 엔진엑스 컨테이너, API 서비스 컨테이너, 젠킨스 컨테이너) 앞서 진행해본 예시대로라는 컨테이너 하나(우분투)에 여러개의 프로세스(엔진엑스, API 서비스 기타 등등)가 실행되므로 권장되는 형태와는 다름을 말씀드립니다.
저희 회사에 구축되어진 개발 환경 또한 하나의 ubuntu, 하나의 rocky linux 서버를 제외하고는 모두 컨테이너당 하나의 프로세스만 구동하는 형식으로 사용하고있습니다.
간단한 사용방법이니만큼 자원을 공유하거나 별도의 네트워크 환경을 구축하는 등 설정은 진행하지 않았습니다. 이후 포스팅에서는 docker의 응용 사용법과 k8s와 결합한 컨테이너 오케스트레이션까지 진행해보도록 하겠습니다.