본문 바로가기

Linux/Docker

docker daemon 설정을 이용해 원격으로 docker 이용하기

시작하며 (이건 스킵하셔도됩니다. 거의 일기장 수준...)

docker clientdocker daemon이 같은 machine에 존재하지 않더라도 docker client를 통해 원격으로 docker를 이용할 수 있다는 내용의 글입니다.
이 글을 읽으시는 분들은 docker에 대한 어느 정도 개념이 있다는 전제하에 글을 적습니다.

Docker를 처음 접했던 건 2019년 봄. 경희대학교는 특이하게 데이터센터 프로그래밍이라는 과목을 통해 DockerKubernetes 를 배울 기회가 주어집니다.(데이터센터 프로그래밍 소개 영상)

당시 컨테이너 관련한 내용은 전무했던 제게 Docker는 너무 재미있는 기술이었습니다. 하지만 많이 어려웠던 것도 사실이었습니다.

Docker, Container을 비롯해 애초에 Web이니 REST API니 Server-Client니 하는 내용들조차 제대로 알지 못하던 상태였기에 다 이해하지 못하고 넘어갔던 부분들이 있었습니다. 그 중 가장 이해가 안 되었던 것이 두 가지 있었습니다.

'나는 그냥 내 컴퓨터에서 도커를 깔아서 쓰고있는데, 왜 도커가 Server-Client 구조의 Application이라는거야?'

'난 HTTP를 이용한 API를 이용한 적이 없는데, 왜 도커가 REST API를 이용한다는 거야?'

이 두 가지 의문이 낳았던 또 다른 궁금증은

'그래 다 이해했다치고, 그럼 Server랑 Client가 떨어져있어도 Client가 Server에게 REST API를 이용해서 원격으로 docker을 이용가능하다는 거야?'

이였고, 교수님께 여쭤보았습니다.. 당시 수업을 맡으셨던 교수님 상당히 스스로 문제해결하는 방법을 찾는 능력을 중시하는 분이셨고, '오! 그 내용은 학생이 한 번 찾아볼래요? 아마 되겠죠? 근데 궁금하긴하네요' 라는 답변을 얻었으나, 당시의 저는 답을 찾을 수 없었습니다 ㅜㅜ.....

그렇게 해당 내용이 머릿 속에서 지워져갈 쯤, docker machine을 이용하면 원격으로 docker command를 이용할 수 있다는 내용으로부터 '아 맞다 옛날에 server/client 구조를 통한 원격 docker 사용이 되나 궁금했는데'하는 생각이 들었고, 1년간 열심히 공부하며 성장한 것인지, 어렵지 않게 답을 얻을 수 있었습니다.

(진짜로) 시작하며

다른 블로그 등에도 모두 정리되어있는 내용이지만 이해를 돕기 위해 다시 한 번 정리하며 간단히 결론부터 요약하자면

  • docker는 server/client 구조로 이루어져있다.
  • docker command는 HTTP라는 프로토콜을 이용하는 REST API이다.예를 들어 우리가 그냥 사용하던 docker ps는 docker server의 GET /api-version/containers 으로 HTTP 요청을 보낸 것과 동일한 방식이다.
  • 보통은 docker daemon(server)와 client가 같은 machine 내에 존재한다.
    하지만 설정을 통해 Client가 원격으로 Server에 docker command을 전달할 수 있다.

이번 글에서는 Client가 원격으로 Docker을 이용해보는 내용을 다룰 것입니다. 다음 글에서는 REST API를 이용하는 지에 대한 증거(log)를 확인해보는 작업을 다룰 것입니다.

작업은 AWS EC2 Ubuntu 18.04를 기준으로 이루어졌습니다.

용어정리

우선 docker host, docker daemon, docker engine 등 헷갈리는 용어가 많기 떄문에 간단히 정리를 하고 넘어가겠습니다.

주관적인 해석을 해보자면, docker host란 docker daemon을 실행하고, 실제로 image를 저장하고 container을 돌리는 machine을 의미

docker daemon은 client에게 받은 docker command(api)를 실행하여 host machine에서 container을 실행시키거나 image 를 pull/rm하는 등의 명령을 내리는 프로그램

docker engine의 경우 Official Docker docs에 의하면 client/server(docker daemon) application 통틀어 docker engine이라고 한답니다.

서버-클라이언트 구조의 Docker

official docker docs에 제시된 그림입니다. 수없이 많이 이 그림을 보았지만, 늘 의문이었고 이제야 이해가 됩니다. 보통은 Client와 Server가 한 machine에 붙어있고 우리 눈에는 REST API를 이용중이라고 느껴지지 않죠.

다만 이 글의 주 내용을 통해 알 수 있듯, Client와 Server(docker daemon)은 같은 host에 존재할 필요도 없고, 따라서 remote server에게 REST API를 통해 명령을 보낼 수 있습니다. 이 때 http 요청 자체를 보낼 수도 있고 docker command를 이용할 수도 있죠. 우리는 주로 docker command를 이용해왔지만, 이것은 docker cli를 통해 REST API를 이용한 셈입니다.

이 내용은 다음 글에서 좀 더 자세히 다뤄볼 생각이에요.

Host의 docker daemon 설정하기

이제 실제로 원격 docker daemon에게 client가 명령을 내리기 위한 작업을 시작해봅시다.

/lib/systemd/system/docker.service 의 내용입니다. 기본적으로는 dockerd(docker daemon)을 이용할 때 containerd.socket을 이용하는 모양이네요.(이부분은 확실치않음..)

Quora-Docker Engine & Docker Daemon에서는 기본적으로 도커엔진은 2376번 포트를 이용한다고 적혀있지만, 도커를 이용하더라도 netstat -ntlp 를 통해 열린 port를 찾아봐도 도커 데몬이 이용하는 포트를 찾을 수 없는 경우가 많았습니다.(앞의 글이라 그런 건지 왜 그런 건진 모르겠지만, 어쨌든 local에서는 unix socket을 이용해 통신하고, 네트워크 통신을 할 때에는 tcp socket을 이용한다고 합니다. - 참고http://pyrasis.com/book/DockerForTheReallyImpatient/Chapter14)

/lib/systemd/system/docker.service 에서 ExecStart= 부분을 아래와 같이 바꾸어줍시다.

dockerddocker daemon, -H는 host로서 자신이 docker daemon의 호스트로서 이용할 IP와 Port을 적어준다. 아래의 코드는 0.0.0.0:2375를 Host로서 docker daemon을 실행하도록 하는 코드입니다.

ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H 0.0.0.0:2375

그리고 변경사항을 적용시켜줍시다. 0.0.0.0:2375는 원격 통신을 할 때 사용하는 호스트이고, unix socket은 local 통신을 할 때 사용하는 socket입니다.

sudo systemctl daemon-reload
sudo systemctl restart docker.service

만약 unix socket을 적어주지 않으면 local에서는 docker command가 제대로 작동하지 않고, IP와 Port를 적어주지 않으면 원격에서 docker command가 제대로 작동하지 않습니다. 아래의 명령어를 통해 변경사항을 적용시켜줍시다.

저의 경우는 AWS EC2 Instance를 이용했기때문에, Security Group에서 제가 설정한 포트인 2375번 포트를 Inbound에서 허용시켜줘야했습니다. 일반 Laptop을 이용해서 사용하실 경우 방화벽이나 포트바인딩문제로 번거로워질 수 있습니다.

docker daemon을 설정하는 방법은 https://serverfault.com/questions/843296/how-do-i-expose-the-docker-api-over-tcpDocker docs - Daemon socket option에도 참 잘 나와있습니다.

저는 docker.service에서 host를 직접 적어준 것이고, 다른 한 가지 방법은 daemon.json이란 파일에 host를 적어주는 방법이 있었습니다.

-H unix://... 이외에 fd://를 이용하는 방법도 바로 위의 Docker docs 링크에 제시되어있습니다.

sudo systemctl restart docker.service 에서 오류가 안났다면 아마 잘 설정되었을 것입니다.

원격으로 docker daemon에게 명령 보내기

docker 가 깔려있는 다른 네트워크 환경의 PC에서 방금 설정한 서버에게 명령을 보내보겠습니다.

0.0.0.0:2375로 docker daemon의 host를 설정하였지만 0.0.0.0자신이 가진 네트워크에 따라 여러 IP를 나타낼 수 있습니다. 저의 경우 15.164.172.173 이라는 IP가 Public IP로 존재하므로 클라이언트는 이를 통해 접속이 가능합니다.

docker --help를 통해 알아보니 -H를 이용해 연결할 host를 설정하라는 군요.

docker -H {DOCKER_HOST_IP} images을 입력해봅시다.

이럴수가..!! 저만 신세계인건가요..? 너무도 쉽게 원격으로 docker daemon을 이용할 수 있나봅니다.

믿기지 않으니 한 번 실제로 원격의 client를 이용해 nginx container을 run 시킨 후 접속해보죠.

docker -H {DOCKER_HOST_IP} run -d -p 80:80 --rm --name nginx-container nginx

(AWS를 이용할 경우 Security groups에서 80번 포트에 대한 Inbound를 허용해주어야합니다.)

위의 사진을 Client가 원격으로 docker daemon에게 ps 명령을 보낸 모습이고,

아래 사진은 docker daemon과 같은 machine에 있는 client가 명령을 보낸 모습입니다.

동일한 결과를 얻을 수 있습니다!!!!

저만 감동인가요 이 내용들..? ㅜㅜ

환경변수를 통한 Docker host 설정

여기서 팁 추가! 환경변수를 이용하면 좀 더 간단하게 docker를 원격으로 이용할 수 있습니다.

DOCKER_HOST라는 환경변수를 설정해주면 됩니다.

환경변수를 설정해주면, 환경변수가 유효한 동안은 -H옵션 없이 편하게 바로 원격으로 docker command를 이용할 수 있습니다.

Alias를 통한 Docker host 설정

이 내용은 docker host를 다루는 어디에서도 못 본 내용인데, docker-compose를 이용할 때 alias를 이용했던 것이 생각나서 제가 적어봅니다.

alias를 이용하면 자주 쓰는 명령어들을 편리하게 사용할 수 있는데요. 이 방법은 사실 거의 Docker geek만을 위한 것일 것 같습니다...

~/.bashrc에서 alias를 설정하고 source ~/.bashrc를 통해 적용해줍시다.

(마지막 줄만 보면 됩니다.) 저는 docker ec2라는 의미에서 dec2를 적어보았습니다.

한 번 여러가지 docker command를 시도해보겠습니다.

사진과 같이 잘 작동하네요. 신기신기!!!!! >_<

마치며

묵혀왔던 궁금증을 해결한 탓에 너무 흥분해서 주절주절 적은 건 아닌가싶기도하네요. 오늘 하루의 탐구 덕에 도커에 대해 좀 더 알아갈 수 있었던 것 같아 기분이 좋습니다.ㅎㅎ

사실 그냥 Dockerfile을 만들고 port binding 만해서 사용하면 누구나 금방 익힐 수 있지만, 이런 deep한 내용도 알면 분명히 다른 기술이나 좀 더 어려운 내용을 접할 때 도움이 될 것이라고 생각합니다.

너무너무 deep하고 흐름을 방해하는 내용들은 약간 생략한 부분도 있고 제가 잘 모르는 부분도 있긴합니다.

예를 들면 unix socket이나 fd://에 대한 내용 등등... 혹시 간략하게 댓글로 설명해주실 분이 계시다면 환영이고, 혹시 저 같은 궁금증을 갖고 계셨던 분이 계시다면 이 글이 도움이 되었으면 좋겠습니다~~

다음 편에서는 docker 가 REST API를 사용하는가에 대해 적어보겠습니다.

참고

각종 도커 documentation-https://docs.docker.com/engine/docker-overview/

가장 빨리 만나는 Docker 14장 Docker Remote API 사용하기-http://pyrasis.com/book/DockerForTheReallyImpatient/Chapter14

docker daemon이란-https://www.quora.com/What-is-the-difference-between-the-Docker-Engine-and-Docker-Daemon

docker daemon 설정법, expose 시키는 법-https://serverfault.com/questions/843296/how-do-i-expose-the-docker-api-over-tcp