본문 바로가기

Linux/Docker

Docker가 REST API를 이용함을 확인해보자

"Docker가 REST API를 이용한다는 글은 많이 봤는데, 솔직히 난 잘 이해가 안돼. 사실인지 알아보고싶어!"

시작하며

docker machinedocker swarm 등에 대해 공부하던 중 우연히 다시금 docker의 구조에 대해 다시 생각해볼 시간을 갖게 되었고, 이에 저번 글에서는 docker가 server-client 구조를 갖는다는 점을 이용해 client가 원격으로 docker을 이용할 수 있다는 내용을 알아보았습니다. 이번엔 docker의 server와 client가 REST API를 이용해 통신한다는 내용에 대해 알아보겠습니다. 구글에 docker rest apidocker remote api 라는 키워드로 검색하면 몇 가지 글이 나오긴하지만, 이해를 명확히 돕는 눈에 보이는 자료들은 부족하다고 느껴져 정리해보겠습니다.

Docker daemon의 log를 통해 실제로 docker가 REST API를 이용하고 있음을 눈으로 확인해보는 내용의 글입니다. 이 글을 읽는 분들은 docker에 대한 어느 정도 개념이 있다는 전제하에 진행합니다.

작업 순서

작업순서는 크게 아래 네 가지 흐름으로 요약할 수 있습니다. 대부분의 작업은 root 권한으로 진행합니다.

  1. 원래 running 중이던 docker daemon을 중지시키고 foreground 모드(백그라운드가 아닌 실시간으로 로그가 보이는 모드)로 run 시킨다.
  2. client가 직접 HTTP Request를 통해 docker API를 이용해본다.
  3. 전 편에서 다뤘듯이 docker daemon과 다른 host의 client에서 원격으로 docker cli를 통해 docker command를 이용해 명령을 내려본다.
  4. log가 같음을 확인한다.

원래 running 중이던 docker daemon을 중지시키고, foreground 모드로 docker daemon을 run 시킨다.

만약 현재 docker daemon(process 이름은 dockerd)가 실행 중이라면, foreground로 dockerd를 다시 실행할 때 에러가 발생합니다.

ps -ef | grep dockerd를 통해 dockerd가 실행 중인지 확인해볼 수 있습니다.

dockerd가 실행 중일 때 foreground로 dockerd를 실행시키려하면 다음의 에러가 발생합니다.

root@ip-172-31-36-180:/home/ubuntu# dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --debug
INFO[2020-03-08T10:26:57.710749235Z] Starting up                                  
failed to start daemon: pid file found, ensure docker is not running or delete /var/run/docker.pid

docker을 종료시키거나 /var/run/docker.pid를 지우랍니다.

docker을 종료하는 방법은 우분투 기준으로 systemctl stop docker.service이고, docker.pid를 지우는 방법은 말 그대로 해당 파일을 지워주면 됩니다.

/var/run/docker.pid는 말 그대로 docker daemon의 process id를 담고 있군요.

성공적으로 background에서 실행 중이던 dockerd를 중지시켰다면 ps -ef | grep dockerd에서 dockerd process가 삭제되었을 것입니다.

원래는 systemctl start docker.service 를 이용해 dockerd를 background에서 돌렸지만 이번엔 실시간으로 로그를 확인해보기 위해 foreground에서 실행시켜보겠습니다.

dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --debug

좀 더 자세한 configuration은 Official docker docs 에서 찾아보실 수 있습니다. 간단히 내용을 말하자면, docker daemon을 foreground mode로 run하는데, 외부에선 tcp://0.0.0.0:2375, 로컬에선 /var/run/docker.sock을 이용하도록 하는 것입니다. 그리고 debug 옵션을 달아준 이유는 제가 확인하고 싶은 로그가 생략되지 않도록 하기 위함입니다.

Client가 직접 HTTP Request를 통해 docker API 이용해보기.

Docker docs endpoints(https://docs.docker.com/engine/api/v1.24/)을 통해 다양한 docker API의 Endpoint에 대한 내용을 참고할 수 있습니다. 방금 제시한 링크는 검색을 통해 나오는 api version 1.24 에 대한 documentation입니다. 하지만, 제가 직접 api를 이용해보니 version 1.40을 이용하길래 해당 documentation의 링크를 1.40으로 바꿔보았더니 좀 더 신 버전의 documentation도 존재하더군요. 필요할 시 참고하시면 되겠습니다.(https://docs.docker.com/engine/api/v1.40/) 저는 1.40 version의 api documentation을 참고했습니다.

documentation에 나온 API 명세 중 일부입니다. /containers/json이라는 endpoint를 통해 container의 목록을 받아올 수 있는 모양입니다. 그리고 Endpoint 자체에 대한 설명을 조금 참고해보자면 다음과 같습니다.

If you omit the version-prefix, the current version of the API (v1.40) is used. For example, calling /info is the same as calling /v1.40/info - docker engine docs

즉 현재 글을 쓰는 시점 기준으로는 endpoint에서 version을 생략하면 기본적으로 v1.40을 이용한다는 것입니다. 저는 그냥 /v.1.40/containers/json 이런 식으로 version을 명시시켜주겠습니다. 그럼 Postman을 통해 한 번 직접 HTTP Request를 만들어보죠.

우와... 이게 진짜 되네..! 현재 container가 존재하지 않아서 빈 array가 리턴되긴했지만, 로그를 보니 요청이 성공적으로 들어왔고 response도 성공적으로 전달된 것을 알 수 있습니다. 그럼 이번엔 container을 생성하고 start 시켜본 뒤 다시 container의 list를 얻어와보겠습니다.

API v1.40에 대한 docs를 참고하여 HTTP Request를 보내어봤습니다.

http://13.125.221.179:2375/v1.40/containers/create?name=nginx-container 는 container 을 create 할 뿐 start 시키진 않습니다.

아까 foreground로 실행시켜놓은 docker daemon에도 log 가 성공적으로 적힌 것 같습니다. 로그의 앞에 DEBUG 라는 Prefix가 적힌 것을 보아 dockerd command를 실행헀을 때 --debug 옵션을 주지 않았더라면 보지 못했을 로그임을 알 수 있습니다.

response로 얻은 Id를 이용해 http://13.125.221.179:2375/v1.40/containers/701572c0dd534757134da87ff8a78ec91229523d25ce9ee07f4eca601a14417e/start 으로 container을 start 시킵시다. start API는 별다른 response가 없군요. 이제 다시 한 번 container list를 얻어오는 API를 이용해보겠습니다. 방금 만든 nginx container가 존재한다면 좋겠네요!

감동의 도가니입니다..!! 다른 내용은 생략하였습니다만 아까 저희가 query로 전달한 name=nginx-container인 컨테이너가 생겨났군요!! 실제로 동작한 지 확인하기 위해서 docker daemon과 같은 host 내에서 docker command 를 이용해 container을 조회해보겠습니다.

docker cli를 통해 command를 수행하는 것과 HTTP Request를 보내는 것은 같은 작업이다.

자, 방금 한 작업에서 우리가 확인할 수 있는 중요한 점이 있습니다. 몇 번 요청을 보내고 command를 수행하면서 로그를 보시면 알게되시겠지만 바로 docker cli 또한 우리가 http request를 만들었던 것과 동일하게 API를 이용한다는 점입니다.

docker ps/v1.40/containers/json 요청 모두 동일한 작업입니다. 즉 우리(저만 간과하고 있었던 것일 수도 있어용ㅎㅎ;;)가 간과하고있었으나 docker cli는 내부적으로 docker API를 이용하고 있었던 것임을 로그를 통해 눈으로 확인할 수 있는 것입니다.

이점, 보완할 점

dockerREST API를 이용한다는 내용을 여기저기서 주워듣기도 해보았고, 이래저래 설명을 하는 글을 보기도 했지만, 내용이 직관적이지 않았고, 실제로 docker cli가 REST API를 이용하고 있는것인지 확인할 수 있는 내용은 찾기 힘들었는데, 이번에 로그를 직접 보면서 좀 더 명확히 이해할 수 있게된 듯 합니다.

이 내용을 통해 별도의 agent를 이용하는 Deploy pipeline을 이용하지 않더라도 docker REST API를 이용해서도 deploy를 진행할 수도 있을 것 같습니다. (하지만 대부분의 경우 agent나 deployment tool 이용하는 게 편해보이긴합니다.)

보완할 점은 현재는 어떤 client라도 expose된 IP:Port를 통해 docker API를 실행할 수 있도록 설정되어있기 때문에, 혹시라도 실제로 사용하시게 된다면, docker REST API를 이용할 수 있는 client IP를 제한하거나 인증과정을 추가하는 등을 통해 보안적 이슈를 조금 신경써줘야할 듯합니다.