본문 바로가기
kubernetes

docker-machine, virtualbox 로 docker cli 환경 구성 (Docker Desktop 유료화, host only network, x509: certificate)

by tango0415 2022. 1. 24.

개요

Docker Desktop 이 유료화를 선언했고, 2022년 2월 1일 부터는 회사 자산의 맥, 윈도우에서는 Docker Desktop 을 무료로 사용할 수 없게 되었습니다. 이에 따라서 다양한 대응 방법들이 소개되고 있습니다.

Docker Client / Server

Docker 는 기본적으로 Client + Server 구조로 동작합니다. 터미널에서 docker container ls 와 같은 명령어를 입력하면, 실제로는 docker 라는 프로그램(Client)이 호스트 머신에 실행중인 dockerd(Server)에 요청을 보내 컨테이너의 목록을 조회해오는 과정이 이뤄집니다.

Docker Desktop 이란, docker 관련된 명령어를 쉽게 수행할 수 있게끔 위와같이 Client + Server 를 설치, 실행해주는 애플리케이션이라고 볼 수 있습니다.

컨셉

Docker Server 를 호스트 머신(맥 or 윈도우)이 아닌 별도의 가상 머신(linux)에 설치해두고, 호스트 머신에서 수행하는 docker 명령어가 해당 서버를 바라보도록 설정해준다면 Docker Desktop 설치없이 로컬에서 docker cli 를 사용할 수 있습니다.

이를 위해서 아래와 같은 툴들이 필요합니다. (맥 기준)

  • brew
  • docker
    • docker client
  • docker-credential-helper
    • docker-client 사용시 인증
  • virtualbox
    • dockerd 설치를 위한 가상 머신 생성 툴
  • docker-machine
    • 가상 머신에 docker 툴들을 프로비저닝

docker, virtualbox, docker-machine 설치, 구성

brew install docker docker-credential-helper --formula
brew install virtualbox --cask

위 과정까지만 진행해보고 docker version 명령어를 수행하면, Client 정보만 나오고, Server 에는 연결 실패했다는 메시지를 볼 수 있습니다.

brew install docker-machine --formula
docker-machine create --driver "virtualbox" default
docker-machine ls

docker-machine create 명령어로 virtualbox 가상머신을 만들고, 가상머신에 docker 세팅을 완료합니다.

docker-machine ls , docker-machine ssh , docker-machine remove 등의 명령어를 통해 생성된 가상머신을 제어할 수 있습니다.

docker-machine 으로 가상머신에 docker server 를 실행하고, docker client 가 해당 서버를 바라보도록 설정하기 위해 몇가지 환경변수를 추가합니다. 이때 생성된 가상머신의 IP 를 넣어줍니다.

# ~/.zshrc
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://${docker-machine ip}:2376"
export DOCKER_CERT_PATH="/Users/user/.docker/machine/machines/default"
export DOCKER_MACHINE_NAME="default"
source ~/.zshrc
docker version

# docker Client, Server 정보가 모두 잘 출력되는것을 확인
Client: Docker Engine - Community
 Version:           20.10.12
 API version:       1.40
 Go version:        go1.17.5
 Git commit:        e91ed5707e
 Built:             Sun Dec 12 06:28:24 2021
 OS/Arch:           darwin/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:49:35 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

위까지 진행했을때, docker-machine 에 연동이 잘 되면 좋겠지만, 제 경우에는 아래와 같은 2가지 문제가 있었습니다.

  • virtualbox 로 생성된 게스트 머신에 IP 를 통해 접근하지 못함
  • docker-machine 으로 실행된 dockerd (Server) 가 HTTPS 로만 접근 가능하고, 게스트 머신의 IP로만 접근 가능하도록 설정되어 있음

트러블슈팅

1. virtualbox 로 생성된 게스트 머신에 IP 를 통해 접근하지 못함

VirtualBox 관리자를 통해 보면 게스트 머신에 NAT, host only 네트워크 어댑터 2개가 생성되어 있습니다.

저의 경우에는 docker-machine create 시에 아래와 같은 에러가 발생했고, 호스트 머신에서 가상머신의 host only 네트워크 "192.168.99.126" 로 접근하지 못하는 알 수 없는 문제가 있었습니다.

❯ docker-machine create --driver "virtualbox" default

Running pre-create checks...
Creating machine...
(default) Copying /Users/user/.docker/machine/cache/boot2docker.iso to /Users/user/.docker/machine/machines/default/boot2docker.iso...
(default) Creating VirtualBox VM...
(default) Creating SSH key...
(default) Starting the VM...
(default) Check network to re-create if needed...
(default) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...

This machine has been allocated an IP address, but Docker Machine could not
reach it successfully.

SSH for the machine should still work, but connecting to exposed ports, such as
the Docker daemon port (usually <ip>:2376), may not work properly.

You may need to add the route manually, or use another related workaround.

This could be due to a VPN, proxy, or host file configuration issue.

You also might want to clear any VirtualBox host only interfaces you are not using.
Checking connection to Docker...
Error creating machine: Error checking the host: Error checking and/or regenerating the certs: There was an error validating certificates for host "192.168.99.126:2376": dial tcp 192.168.99.126:2376: i/o timeout
You can attempt to regenerate them using 'docker-machine regenerate-certs [name]'.
Be advised that this will trigger a Docker daemon restart which might stop running containers.

디버그를 위해 ssh 로 접속해서 가상머신의 상태를 확인할 수 있습니다.

host only 네트워크로 접근하지 못하는 문제를 해결하기 위해 NAT 네트워크에 dockerd (2376 포트)와의 포트포워딩 설정을 추가하였습니다.

~/.zshrc 에 아래 내용을 추가하고 docker version 명령어를 입력해보면 연동은 되지만, 인증 에러가 발생합니다.

❯ vim ~/.zshrc
~                                                                                                                                                                          
❯ source ~/.zshrc
~                                                                                                                                                                              16:04:33
❯ docker version
Client: Docker Engine - Community
 Version:           20.10.12
 API version:       1.41
 Go version:        go1.17.5
 Git commit:        e91ed5707e
 Built:             Sun Dec 12 06:28:24 2021
 OS/Arch:           darwin/amd64
 Context:           default
 Experimental:      true
error during connect: Get "https://127.0.0.1:2376/v1.24/version": x509: certificate is valid for 192.168.99.126, not 127.0.0.1

2. docker-machine 으로 실행된 dockerd (Server) 가 HTTPS 로만 접근 가능하고, 게스트 머신의 IP로만 접근 가능하도록 설정되어 있음

docker-machine 을 통해 실행된 dockerd 프로세스가 https 설정, cert 설정이 되어 있어서 위의 문제가 발생하고 있습니다. docker-machine ssh default 명령어를 통해 가상머신에 접근하여 확인해보면 아래와 같습니다.

root      2689     1  0 06:46 ?        00:00:00 dockerd --data-root /var/lib/docker -H unix:// --label provider=virtualbox -H tcp://0.0.0.0:2376 --tlsverify --tlscacert=/var/lib/boot2d
ocker/ca.pem --tlskey=/var/lib/boot2docker/server-key.pem --tlscert=/var/lib/boot2docker/server.pem --storage-driver overlay2 --pidfile /var/run/docker.pid

kill -9 명령어로 종료하고 다시 dockerd 프로세스를 실행해봅니다.

docker@default:~$ sudo kill -9 2689
docker@default:~$ sudo dockerd --data-root /var/lib/docker -H unix:// --label provider=virtualbox -H tcp://0.0.0.0:2376 --tls=false --storage-driver overlay2 --pidfile /var/run/docker.pid &

zshrc 내의 환경변수 "DOCKER_TLS_VERIFY" 를 emptyString "" 으로 설정해주고 적용하면 아래처럼 잘 연동이 되는 것을 확인할 수 있습니다.

결론

Docker Desktop 유료화를 우회하는 컨셉 자체는 대부분 비슷한 것 같습니다. docker-machine 툴이 아니라 minikube 를 써도 virtualbox 위에서 동일하게 구성이 가능해보입니다.

주의할 점은 호스트 머신에 도커 컨테이너가 뜨는 방식이 아니라서, 도커 컨테이너에 접근하기 위해서는 virtualbox 포트 포워딩을 추가해줘야 하는 수고가 필요합니다.

Docker 명령어가 동작하는 구조, 호스트 머신과 가상 머신의 네트워크에 대한 이해가 이슈 해결에 많이 도움되었는데요. 대부분은 host only 네트워크에 잘 붙으실텐데, 저처럼 알 수 없는 이유로 접근하지 못하는 경우 NAT + 포트포워딩을 통해서 해결할 수 있음을 공유해보았습니다.