article thumbnail image
Published 2021. 1. 18. 15:44

docker run ubuntu:16.04

run명령어를 사용하면 사용할 이미지가 저장되어 있는지 확인하고

없다면 다운로드(pull)를 한 후 컨테이너를 생성(create)하고 시작(start) 합니다.

 

위 예제는 ubuntu:16.04 이미지를 다운받은 적이 없기 때문에 이미지를 다운로드 한 후 컨테이너가 실행되었습니다. 컨테이너는 정상적으로 실행됐지만 뭘 하라고 명령어를 전달하지 않았기 때문에 컨테이너는 생성되자마자 종료됩니다. 컨테이너는 프로세스이기 때문에 실행중인 프로세스가 없으면 컨테이너는 종료됩니다.

 

이번에는 /bin/bash 명령어를 입력해서 ubuntu:16.04 컨테이너를 실행해 보겠습니다.

 

 

컨테이너 내부에 들어가기 위해 bash 쉘을 실행하고 키보드 입력을 위해 -it 옵션을 줍니다. 추가적으로 프로세스가 종료되면 컨테이너가 자동으로 삭제되도록 --rm 옵션도 추가하였습니다.

 

이번에는 바로 전에 이미지를 다운 받았기 때문에 이미지를 다운로드 하는 화면 없이 바로 실행되었습니다. 

cat /etc/issue와 ls를 실행해보면 ubuntu 리눅스인걸 알 수 있습니다. 뭔가 가벼운 가상머신 같나요?

exit로 bash 쉘을 종료하면 컨테이너도 같이 종료됩니다.

도커를 이용하여 가장 기본적인 컨테이너를 순식간에 만들어 보았습니다.

 

redis container

2번째 컨테이너는 redis 입니다. redis는 메모리기반의 다양한 기능을 가진 스토리지입니다. 6379 포트로 통신하며 telnet 명령어로 테스트해 볼 수 있습니다. redis 컨테이너는 detached mode(백그라운드 모드)로 실행하기 위해 -d 옵션을 추가하고 -p 옵션을 추가하여 컨테이너의 포트를 호스트의 포트로 연결해보겠습니다.

 

-d 옵션이 없다면 프로세스가 foreground로 실행되어 아무키도 입력할 수 없게 됩니다. 컨테이너를 종료하려면 ctrl + c를 입력해 주세요.

 

-d 옵션을 주었기 때문에 컨테이너를 실행하자마자 컨테이너의 ID(ebe1407...)를 보여주고 바로 쉘로 돌아왔습니다.

 

컨테이너는 종료된 것이 아니라 백그라운드 모드로 동작하고 있고 컨테이너 ID를 이용하여 컨테이너를 제어할 수 있습니다. 

 

-p 옵션을 이용하여 호스트의 1234포트를 컨테이너의 6379포트로 연결하였고

localhost의 1234포트로 접속하면 하면 redis를 사용할 수 있습니다.

 

테스트 결과 redis에 접속하여 새로운 키를 저장하고 불러오는데 성공했습니다. 실행이 간단한건 물론이고 호스트의 포트만 다르게 하면 하나의 서버에 여러개의 redis 서버를 띄우는 것도 매우 간단합니다.

 

MySQL 5.7 container

3번째 실행할 컨테이너는 MySQL 서버입니다.

가장 흔하게 사용하는 데이터베이스인데 이번에는 -e 옵션을 이용하여 환경변수를 설정하고 --name 옵션을 이용하여 컨테이너에 읽기 어려운 ID 대신 쉬운 이름을 부여할 예정입니다.

 

--name옵션을 생략하면 도커가 자동으로 이름을 지어 줍니다. 이름은 유명한 과학자나 해커의 이름과 수식어를 조합하여 랜덤으로 생성합니다. (ex - boring_wozniak) 우리나라 과학자 장영실도 등록되어 있습니다.

 

MySQL Docker hub 페이지에 접속하면 간단한 사용법과 환경변수에 대한 설명이 있습니다. 여러가지 설정값이 있는데 -e 옵션을 주어 패스워드 없이 root계정을 만들기 위해 MYSQL_ALLOW_EMPTY_PASSWORD 환경변수를 설정합니다. 그리고 컨테이너의 이름은 mysql로 할당하고 백그라운드 모드로 띄우기 위해 -d 옵션을 줍니다. 포트는 3306포트를 호스트에서 그대로 사용하겠습니다

 

와우, 순식간에 MySQL서버가 실행되었습니다. 이번 테스트는 호스트 OS에 MySQL 클라이언트가 설치되어 있어야 합니다. 추후에 실행중인 MySQL 도커 컨테이너에 접속하여 클라이언트를 실행해 보도록 하겠습니다.

 

tensorflow

마지막으로 이렇게 활용할 수 있다라는 예제로 tensorflow를 실행보도록 하겠습니다. tensorflow는 손쉽게 머신러닝을 할 수 있는 툴입니다. tensorflow는 python으로 만들어져 python과 관련 패키지를 설치해야 합니다. 이번에 설치하는 이미지는 python과 함께 numpy, scipy, pandas, jupyter, scikit-learn, gensim, BeautifulSoup4, Tensorflow가 설치되어 있습니다. 뭔가 복잡해 보이지만 도커라면 손쉽게 실행해 볼 수 있습니다.

 

설치된 파일이 많아 다운로드 하는데 시간이 좀 걸립니다. 컨테이너가 실행되면 웹 브라우저에서 jupyter에 접속하여 머신러닝을 시작해 봅시다!

 

여기까지 ubuntu, MySQL, redis, Wordpress, tensorflow를 실행해 보았습니다. 가상머신을 이용해서 동일한 작업을 했다면 컴퓨터가 엄청나게 버벅이기 시작했겠지만 컨테이너 기반의 도커를 이용하여 매우 가볍게 실행하고 있습니다. 내부 구조나 설치과정은 자세히 모르지만, 간단한 도커 명령어로 여러개의 서비스를 순식간에 실행하고 사용할 수 있다니 정말 짱짱맨입니다.


명령어

컨테이너 목록 확인하기 (ps)

docker ps

 

ps 명령어는 실행중인 컨테이너 목록을 보여줍니다. detached mode로 실행중인 컨테이너들이 보입니다. 어떤 이미지를 기반으로 만들었는지 어떤 포트와 연결이 되어있는지 등 간단한 내용을 보여줍니다.

이번에는 -a 옵션을 추가로 실행해보겠습니다.

 

docker ps -a

 

맨 처음 실행했다가 종료된 컨테이너(Exited (0))가 추가로 보입니다. 컨테이너는 종료되어도 삭제되지 않고 남아있습니다. 종료된 건 다시 시작할 수 있고 컨테이너의 읽기/쓰기 레이어는 그대로 존재합니다. 명시적으로 삭제를 하면 깔끔하게 컨테이너가 제거됩니다.

 

컨테이너 중지하기 (stop)

실행중인 컨테이너를 중지하는 명령어는 다음과 같습니다.

 

docker stop [OPTIONS] CONTAINER [CONTAINER...]

 

옵션은 특별한게 없고 실행중인 컨테이너를 하나 또는 여러개 (띄어쓰기로 구분) 중지할 수 있습니다.

 

앞에서 실행한 tensorflow 컨테이너는 더이상 필요가 없으니 중지해 보겠습니다. 중지하려면 컨테이너의 ID 또는 이름을 입력하면 됩니다. tensorflow 컨테이너의 ID를 ps명령을 통해 확인하고 중지해 봅니다.

 

docker ps # get container ID
docker stop ${TENSORFLOW_CONTAINER_ID}
docker ps -a # show all containers

도커 ID의 전체 길이는 64자리 입니다. 하지만 명령어의 인자로 전달할 때는 전부 입력하지 않아도 됩니다. 예를 들어 ID가 abcdefgh...라면 abcd만 입력해도 됩니다. 앞부분이 겹치지 않는다면 1-2자만 입력해도 됩니다.

 

컨테이너 제거하기 (rm)

종료된 컨테이너를 완전히 제거하는 명령어는 다음과 같습니다.

docker rm [OPTIONS] CONTAINER [CONTAINER...]

종료 명령어도 옵션은 특별한게 없습니다.

종료된 컨테이너를 하나 또는 여러개 삭제할 수 있습니다.

종료된 ubuntu 컨테이너와 tensorflow 컨테이너를 삭제해보겠습니다.

docker ps -a # get container ID
docker rm ${UBUNTU_CONTAINER_ID} ${TENSORFLOW_CONTAINER_ID}
docker ps -a # check exist

컨테이너가 말끔히 삭제되었습니다. 호스트 OS는 아무런 흔적도 남아있지 않고 컨테이너만 격리된 상태로 실행되었다가 삭제되었습니다. 시스템이 꼬일 걱정이 없습니다.

중지된 컨테이너를 일일이 삭제 하는 건 귀찮은 일입니다. docker rm -v $(docker ps -a -q -f status=exited) 명령어를 입력하면 중지된 컨테이너 ID를 가져와서 한번에 삭제합니다.

이미지 목록 확인하기 (images)

도커가 다운로드한 이미지 목록을 보는 명령어는 다음과 같습니다.

 

docker images

이미지 주소와 태그, ID, 생성시점, 용량이 보입니다. 이미지가 너무 많이 쌓이면 용량을 차지하기 때문에 사용하지 않는 이미지는 지우는 것이 좋습니다.

이미지 다운로드하기 (pull)

이미지를 다운로드하는 명령어는 다음과 같습니다.

docker pull [OPTIONS] NAME[:TAG|@DIGEST]

ubuntu:14.04를 다운받아보겠습니다.

docker pull ubuntu:14.04

run명령어를 입력하면 이미지가 없을 때 자동으로 다운받으니 pull명령어를 언제 쓰는지 궁금할 수 있는데 pull은 최신버전으로 다시 다운 받습니다. 같은 태그지만 이미지가 업데이트 된 경우는 pull명령어를 통해 새로 다운받을 수 있습니다.

이미지 삭제하기 (rmi)

이미지를 삭제하는 방법은 다음과 같습니다.

docker rmi [OPTIONS] IMAGE [IMAGE...]

images 명령어를 통해 얻은 이미지 목록에서 이미지 ID를 입력하면 삭제가 됩니다.

단, 컨테이너가 실행중인 이미지는 삭제되지 않습니다.

컨테이너는 이미지들의 레이어를 기반으로 실행중이므로 당연히 삭제할 수 없습니다.

tensorflow는 더 이상 사용하지 않으니 이미지를 제거해보겠습니다.

 

이미지가 삭제되었습니다. 이미지는 여러개의 레이어로 구성되어 있기 때문에 모든 레이어가 삭제된 것을 알 수 있습니다.

컨테이너 둘러보기

도커에 대한 아주아주아주 기본적인 명령어를 살펴보았습니다. 사실 저 명령어들과 이번에 살펴볼 log, exec 명령어를 익히면 도커에서 사용하는 명령어는 거의 다 익혔다고 할 수 있습니다. 다른 명령어는 필요에 따라 하나하나 살펴보면 됩니다.

컨테이너 로그 보기 (logs)

컨테이너가 정상적으로 동작하는지 확인하는 좋은 방법은 로그를 확인하는 것 입니다. 로그를 확인하는 방법은 다음과 같습니다.

docker logs [OPTIONS] CONTAINER

기본 옵션과, -f, --tail 옵션을 살펴봅니다.

 

기존에 생성해 놓은 우분투 로그를 확인해 보겠습니다.

docker ps
docker logs ${UBUNTU_CONTAINER_ID}

 

컨테이너에서 실행한 로그가 쭈욱 보입니다.

아무 옵션을 주지 않았을 때는 전체 로그를 무식하게 전부 다 출력합니다. 너무 많으니 --tail옵션으로 마지막 10줄만 출력해 보겠습니다.

 

마지막 10줄만 보니 좀 나아 보입니다. 이제 실시간으로 로그가 생성되는 걸 확인해보겠습니다. -f 옵션으로 실행합니다.

 

로그를 켜 놓은 상태에서 워드프레스 페이지를 새로고침하면 브라우저 접속 로그가 실시간으로 보입니다. 가장 흔하게 사용하는 옵션이고 로그 보기를 중지하려면 ctrl + c를 입력하면 됩니다.

 

로그에 대해 좀 더 자세히

프로그램마다 로그 파일은 제각각 생길텐데 어떻게 저 로그가 나올까 라는 의문이 생깁니다. 도커는 로그파일을 자동으로 알아채는게 아니라 표준 스트림Standard streams  stdout, stderr를 수집합니다. 따라서 컨테이너에서 실행되는 프로그램의 로그 설정을 파일이 아닌 표준출력으로 바꾸어야 합니다. 단지 출력 방식만 바꾸는 것으로 모든 컨테이너는 로그에 대해 같은 방식으로 관리할 수 있게 됩니다.

 

또 하나 중요한 점은 컨테이너의 로그파일은 json 방식으로 어딘가에 저장이 됩니다. 로그가 많으면 은근히 파일이 차지하는 용량이 커지므로 주의해야합니다. 도커는 다양한 플러그인을 지원하여 json이 아닌 특정 로그 서비스에 스트림을 전달할 수 있습니다. 어느 정도 앱의 규모가 커지면 기본적인 방식 대신 로그 서비스를 이용하는 걸 고려해야 합니다.

컨테이너 명령어 실행하기 (exec)

컨테이너를 관리하다 보면 실행중인 컨테이너에 들어가보거나 컨테이너의 파일을 실행하고 싶을 때가 있습니다. 컨테이너에 SSH를 설치하면 되지 않을까? 라고 생각할 수 있지만 SSH는 권장하지 않습니다. 하지 말라고 하면 꼭 하는 분들이 있던데 제발.. 예전에는 nsenter라는 프로그램을 이용하였는데 docker에 exec라는 명령어로 흡수되었습니다.

컨테이너 명령어를 실행하는 방법은 다음과 같습니다.

 

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

run 명령어와 유사해 보입니다.

차이는 run새로 컨테이너를 만들어서 실행하고 exec실행중인 컨테이너에 명령어를 내리는 정도입니다.

 

일단, 가볍게 실행중인 MySQL 컨테이너에 접속해보겠습니다.

 

키보드 입력이 필요하니 run 명령어와 마찬가지로 -it 옵션을 주었고 bash 쉘로 접속하여 마치 가상머신에 들어온 것 같은 느낌이 듭니다.

접속한 이후에는 어떤 작업도 할 수 있고 컨테이너를 마음껏 건드릴 수 있습니다.

쉘로 완전한 권한을 얻는 방법말고 바로 mysql명령어를 실행 할 수도 있습니다.

 

이제, 호스트 OS에 mysql을 설치하지 않아도 mysql 클라이언트를 사용할 수 있습니다.

굳이 복잡한 작업이 필요 없는 경우는 -it 옵션없이 단순하게 명령을 실행하고 종료할 수도 있습니다.

 

Docker Compose

지금까지 도커를 커맨드라인에서 명령어로 작업했습니다. 지금은 간단한 작업만 했기 때문에 명령이 길지 않지만 컨테이너 조합이 많아지고 여러가지 설정이 추가되면 명령어가 금방 복잡해집니다.

도커는 복잡한 설정을 쉽게 관리하기 위해 YAML방식의 설정파일을 이용한 Docker Compose라는 툴을 제공합니다. 깊게 파고들면 은근 기능이 많고 복잡한데 이번에는 아주 가볍게 다루고 지나가도록 하겠습니다.

 

 

설치하기

Docker for Mac 또는 Docker for Windows를 설치했다면 자동으로 설치됩니다. 리눅스의 경우 다음 명령어를 입력하여 설치합니다. 그냥 설치파일 하나 다운받으면 됩니다.

curl -L "https://github.com/docker/compose/releases/download/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
# test
docker-compose version

 

docker-compose.yml 파일

version: '2'

services:
    db:
        image: mysql:5.7
        volumes:
            - db_data:/var/lib/mysql
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: wordpress
            MYSQL_DATABASE: wordpress
            MYSQL_USER: wordpress
            MYSQL_PASSWORD: wordpress
    wordpress:
        depends_on:
            - db
        image: wordpress:latest
        volumes:
            - wp_data:/var/www/html
        ports:
            - "8000:80"
        restart: always
        environment:
            WORDPRESS_DB_HOST: db:3306
            WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:
    wp_data:

 

 

와우, 아주 손쉽게 워드프레스가 만들어 졌습니다. 단지 명령어를 설정파일로 바꾼거에 불과하지만 가독성과 편리성은 훨씬 향상되었습니다.

Docker Compose의 다른 기능과 생소한 설정내용은 숙제로 남겨드립니다. 원래 개발공부라는게 왠만큼 했다고 생각하면 또 다른게 나오고 끊임없이 공부해야 하는 분야입니다. 화이팅! 도커에 대해 이해를 했다면 Docker Compose 또한 쉽게 사용할 수 있을 것입니다.

 

 

ref : subicura.com/2017/01/19/docker-guide-for-beginners-2.html

 

복사했습니다!