Vagrant, Docker 및 Arkade를 활용한 일회용 로컬 개발 환경 (feat. MySQL 설치 5번한 좌충우돌 스토리)

microwavestine
14 min readDec 28, 2021

--

https://iximiuz.com/en/posts/how-to-setup-development-environment/

위 블로그 내용이 개발 환경 셋업 하는데 도움이 되어서, 저자의 허락 하에 한글 번역하여 공유 합니다. 번역글 뒤에는 개인적으로 업무중 MySQL 을 설치하면서 겪은 일도 함께 작성했습니다.

저는 개발 업무를 할때 (꽤 오래된) 맥북을 사용하고 있습니다. 하지만 제 호스트 OS 에는 개발 관련된 것들을 담아두지 않으려 합니다. 이 전략은 다음과 같은 장점이 있습니다:

  • 코드의 재현성을 높일 수 있다 — 과거에 코드가 제 머신에는 작동하지만 다른 분들 머신에서는 작동하지 않았던 일들이 종종 있었습니다. 주로 missing dependency 이슈 때문이었는데요. 한 머신에 여러 프로젝트를 관리하면 어떤 프로젝트에 어떤 라이브러리와 패키지가 필요한지 관리하기 어려워 집니다. 그래서 저는 프로젝트 당 한 가상머신을 두려고 합니다.
  • 타킷 플랫폼에 코드 테스트를 할 수 있다 — 제가 하고 있는 대부분의 프로젝트는 서버사이드나 인프라와 관련된거라서, 사실 타킷 플랫폼은 리눅스 입니다. 저는 맥북을 사용하지만, 대부분의 시간을 저의 서버들과 같은 OS 를 갖춘 VM들속에서 보내기 때문에, 맥에 있는 데브툴을 각 리눅스 OS 에서 재현합니다.
  • 호스트 OS 를 깨긋하게 유지합니다 — 플랫폼에 구애받지 않는 CLI 툴 같은 프로젝트 작업을 하더라도, 저는 제 워크스테이션을 데브툴과 패키지들로 더렵히지 않으려 합니다. 프로젝트들과 도메인 들은 자주 바뀌기 때문에, 필요한 것들을 바로 호스트 OS 에 다운 받으면 빨리 더럽펴 질수 있습니다.
  • 문제가 생겼을 경우 리커버리 시간을 줄일 수 있다 — 하나의 다목적 머신은 빨리 “스노우플레이크 (눈송이) 호스트”가 됩니다. 문제가 발생했을때 다시 설치 해야하는 목록을 만드는건 어렵습니다.

주로 여러 프로젝트를 동시에 진행하기 때문에, 저는 하나가 아닌 여러 격리된 개발 환경이 필요로 합니다. 그리고 각 환경은 프로젝트에 딱 맞게 만들어져야하고, 쉽게 만들고, 멈추고, 없앨 수 있어야 합니다. 이렇게 할 수 있는 방법을 호스트 머신에 최소한의 툴을 설치하고 진행 할 수 있는 방법을 공유하려 합니다.

이 방법은 맥이나 리넉스를 사용중인 분들, 특히 이런 분들에게 도움이 될 수 있습니다:

  • 서버 사이드 / 풀 스택 프로젝트 진행하시는 분들
  • 리눅스 시스템 프로그래밍 하시는 분들
  • Cloud Native stack 을 재미로 다뤄보시는 분들
  • …멋진 CLI 툴을 만들기 위해서!

TL;DR 중요한 포인트

  • Docker 를 사용하는 이유…
  • 툴을 설치하지 않고 실행해보기 위해서
  • 여러 프로그래밍 언어를 실험해보기 위해서
  • docker-compose 로 이것저것 해보기 위해서
  • Vagrant 를 사용하는 이유: 격리될 수 있고, 멈추고 재생할 수 있는 개발 환경을 위해서
  • arkade 를 사용하는 이유: Kubernetes clusters 를 빨리 만들기 위해서

호스트 OS 에 설치해야 하는 것들

매일 사용하는 브라우저나 미디어 재생 앱 빼고는, 아래의 툴들만 호스트 OS 에 설치합니다.

  • Docker
  • Vagrant
  • code editors (Vim, Sublime Text, Visual Studio Code, etc.)

위에 설명한 이유대로, 이 리스트는 짧습니다. 아마 이 즘 되면 중요한 툴은 Vagrant 인게 명확해 지셨을 겁니다. 하지만 Docker 도 제 맥에 설치 되어 있습니다.

도커를 호스트 OS 에 설치한 이유

  • 랜덤한 툴을 설치하지 않고 실행할 수 있다(e.g., alias jq=’docker run -i stedolan/jq’).
  • 프로그래밍 언어의 여러 버젼들을 풀 셋업 없이 실험해 볼 수 있다
  • docker-compose 로 빨리 멀티 컨테이너 플레이그라운드를 만들 수 있다.

도커는 내가 실행하는 것들을 믿을 수 있다는 전제 하에 꽤 괜찮은 분리 (isolation)를 제공해주고, 필요하지 않은 컨테이너나 이미지들을 쉽게 없앨 수 있습니다. 언젠가는 도커 대신 Podman 을 사용할 생각이지만, 최근 도커가 개발자 경험을 중요시 하겠다는 약속 때문에 아직은 도커에 희망이 있습니다.

시도 해봤지만 결국 Docker + Vagrant를 선택하게 만든 방법들:

  • homebrew —요즘 뭐 설치 하려면 왜 이렇게 오래 걸리나요…
  • rvm, nvm, gvm, etc — 프로그래밍 언어의 여러 버젼들을 관리하기에 괜찮은 옵션이지만, 조심스럽게 다루어야 합니다.
  • Python’s venv — 위와 같지만 파이선 버젼 매니저도 필요합니다. 찾아보려하지도 않았어요;;
  • 컨테이너 안에 개발환경 구축하기 — 해봤지만..개인적으로 컨테이너는 프로젝트를 관리하기에는 너무 일시적인 환경인것 같습니다.

Vagrant 가 사용 되는 방법

Vagrant 는 가상머신들을 개발 환경으로 쉽게 활용 할 수 있게 해줍니다. 저는 VirtualBox provider 와 함께 사용 하기도 합니다. Vagrant 는 homebrew 또는 공식 사이트에서 배포된 버젼을 다운 받을 수 있습니다. 추가적으로, 전 항상 호스트 폴더를 가상 머신에 마운팅하기 위해 VirtualBox Guest Additions plugin 을 다운 받습니다.

$ vagrant plugin install vagrant-vbguest

프로젝트에 뭐가 필요할지 잘 모를때, 일단 최소한의 가상머신으로 시작합니다.

$ mkdir project-skunkworks
$ cd project-skunkworks
$ vagrant init debian/buster64
# vagrant init centos/7
# vagrant init alpine/alpine64
# etc

위 처럼 입력하면 새로운 Vagrantfile 이 생성되고 안에는 가상머신의 구성 정보가 담겨있습니다. 이후에 주로 이렇게 변경합니다:

  • 새로운 가상머신에 의미있는 이름을 부여합니다.
  • 브리지 애덥터를 통해 호스트와의 네트워크를 연결합니다.
  • 프로젝트 폴더를 머신에 마운트 합니다.
  • CPU 와 RAM 자원을 수정합니다.
  • 기본 패키지 목록이 있는 프로비저닝 도구를 추가합니다.
  • 도커 또는 Podman 브로비져너를 추가합니다 (선택 항목).

일반적으로 제 Vagrantfile 은 이렇게 생겼습니다.

Vagrant.configure("2") do |config|
config.vm.box = "debian/buster64"
config.vm.hostname = "skunkworks-01"
config.vm.define "skunkworks-01"
config.vagrant.plugins = ['vagrant-vbguest']
config.vm.network "private_network", ip: "192.168.33.10" config.vm.synced_folder "./", "/home/vagrant/project" config.vm.provider "virtualbox" do |vb|
vb.cpus = 4
vb.memory = "2048"
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y curl git cmake tmux vim # ...
SHELL
config.vm.provision "docker" do |d|
d.run "nginx"
end
end

네, 도커가 가상머신 안에서 돌아도 괜찮습니다! 그리고 도커 설치 방법은 “docker” provisioner 를 파일 안에 적어 놓는 것만큼 간단합니다. 나머지는 Vagrant가 자동으로 해결 해줍니다.

NB 1:”shell” 과 “docker” 가 프로비져닝의 다는 아닙니다. Vagrant 는 여러 프로비젼들을 제공하고 있고, ansible playbook 도 그 중 하나 입니다.

Vagrantfile 을 프로젝트의 나머지 파일과 같이 커밋하려 노력합니다. 왜냐하면 다른 개발자들도 빨리 개발환경을 구축하게 될 수 있기 때문입니다. 프로젝트의 dependency 리스트가 명확해질 때즘, Vagrantfile 을 새 요구사항에 맞게 수정합니다.

Vagrantfile 에서 가상머신을 시작하기 위해, Vagrantfile 이 있는 폴더에서 vagrant up을 실행합니다. 첫 시작은 초기 프로비져닝을 해야해서 몇 분 걸리지만, 이후에 시작 시간은 훨씬 빨라집니다. 가상머신에 접근해서 명령어를 수행하기 위해서는 vagrant ssh를 사용합니다. 실제로 이루어지는 코드 수정/편집은 호스트 OS 에서 코드 에디터를 통해 이루어 집니다. 가상머신 안에서 웹서비스를 구동 한다면, 호스트의 브라우저에서도 Vagrantfile 에 명시한 IP 주소를 통해 접근할 수 있습니다.

구동중인 가상머신은 꽤 많은 CPU 와RAM 자원을 사용하기 때문에 동시에 돌리는 가상머신들을 최소화 하려 합니다. vagrant halt 를 사용해서 가상머신을 셧다운 할 수 있고, vagrant up로 다시 부팅 할 수 있습니다. 조금더 고급스러운 사용방법은 vagrant suspend를 사용해서 가상머신을 일시정지한 후 vagrant resume으로 다시 재생 하는 겁니다.

멈춘 가상머신은 디스크 공간을 차지 할 수 있기 때문에, 프로젝트가 오랫동안 다시 진행 되지 않을 것 같을땐 vagrant destroy를 해서 Vagrantfile 을 제외한 모든 걸 삭제합니다.

NB 2: 가상머신 안에서 개발하면 또 좋은 점은, 스크립트나 코드에서 대환장 실수를 할 경우에도 사실 아무것도 잃지 않는 다는 겁니다

또 다른 유용한 명령어는 vagrant global-status입니다. 위 명령어들과는 다르게 굳이 Vagrantfile 이 있는 폴더 내에서 실행 하지 않아도 되는 명령어 입니다. 저는 가끔 어떤 가상머신들이 살아있는지 확인하기 위해 사용합니다.

Vagrantifile 들은 일종의 Infrastructure as Code 입니다. 이 말은, 최신의 Vagrantfile 을 가지고 있음으로 어떤 환경을 수동적으로 재구성할 필요 없이 재생산 해낼 수 있다는 의미 이기도 합니다. 고로, 제대로 활용만 한다면 Vagrant 개발 환경은 완전히 일회용으로도 사용 될 수 있습니다.

Vagrant 와 Visual Studio Code 원격 개발

Vim 을 사용하지 않을때는 Sublime Text 또는 Visual Studio Code를 사용합니다. 둘 다 완전한 그래픽 UI 를 요구하기 때문에, 코드 에디터는 호스트 OS 에서 사용해야만 합니다.

프로젝트 폴더가 가상머신에 마운트된 상태에서는 코드 에디터에서 이 폴더를 열고 로컬에서 쉽게 수정 할 수 있습니다. 하지만, 좀 복잡한 프로젝트에서는 코드 이외의 툴들 — 린터, 포맷터, 코드 완성 서버 등등 — 을 종종 필요로 합니다. 해당 툴들을 호스트에 설치하는건 일회용 개발 환경을 만든 목적을 아무 의미 없게 만들겠죠…?

그래서 Visual Studio Code 원격 개발이 있습니다!

Visual Studio Code Remote — SSH extension 는 Vagrant 와 아주 잘 작동 합니ㄷExtension 을 설치한 후 vagrant ssh-config덤프를 통해 가상머신에 접속하는 방법을 알려주면 끝입니다!

가상 머신의 SSH credentials 제공 후, Extension 은 자동으로 가상머신에 VS Code Server 를 설치합니다. VS Code 와 이 서버의 페어링을 통해 코드를 실행하고, 패키지를 설치하고 툴들을 원격으로 원할하게 실행할 수 있습니다.

Arkade 가 사용 되는 방법

저는 자주 Cloud Native stack 을 이용해 재미삼아 실험, 개발 합니다. 이럴때 In both arkade 가 꽤 유용합니다. arkade 는 kubectl, kustomize, helm, kind 와 같은 CLI 툴 들을 다운받고 설치 할 수 있는 바이너리 입니다. 또 몇 십가지 helm 차트가 있기 때문에 docker registry, grafana, traefik2, 심지어 linkerd 또는 istio service mesh 를 쿠버네티스 클러스터에 단 하나의 arkade 명령어로 설치할 수 있습니다. 더이상 새로운 설치 방법을 찾기 위해 인터넷을 돌아다닐 필요가 없죠!

arkade 설치 방법 자체도 단 하나의 명령어 입니다

$ curl -sLS https://get.arkade.dev | sudo sh$ arkade --help

이제 가상머신에 이미 도커가 실행 중이라는 가정하에, Nginx Ingress Controller가 있는 쿠버네티스 클러스터를 수십초 만에 만들 수 있습니다!

$ arkade get kubectl
$ arkade get kind
$ kind create cluster$ arkade install ingress-nginx$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-controller-7d98fb5bd-956fq 1/1 Running 0 38s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller LoadBalancer 10.96.239.161 <pending> 80:31973/TCP,443:31901/TCP 38s
service/ingress-nginx-controller-admission ClusterIP 10.96.11.19 <none> 443/TCP 38s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 84s
...

빠른 실험을 해야할때 굉장히 유용하게 사용하고 있습니다. arkade 에 대해 알게 되었을때 더이상 로컬 쿠버네티스 클러스터를 망칠거라는 두려움에 사로잡히지 않는 심리적 해방감을 느꼈습니다. 왜냐하면 몇개의 arkade get/install 명령어로 제 셋업을 다시 만들 수 있게 되었기 때문입니다.

arkade 의 파워와 일회용 Vagrant 가상머신은 제 프로젝트들의 초창기 시절에 빨리 움직일 수 있게 해주었습니다.

MySQL 사건의 전말

현재 회사에서 백엔드 팀은 한달간 리팩토링을 진행 중이고, 리팩토링 항목 중TypeORM 적용이 있어 개발 DB 를 로컬 환경에 구축해 테스트 진행하기 위해 호스트 머신에 MySQL 을 설치했습니다.

무슨 이유에서인지 잘 작동하지 않아서 MySQL 5.7 도 다운 해보고, 지웠다 설치했다가 반복하는 과정에서 어디에서 꼬인건지 알 수 가 없어 디스크 포맷을 하면서

아 맞다, 이 블로그 포스트대로 개발 환경을 구축하면 MySQL 설치 과정에서 무엇이 잘못 되었는지 알 수 도 있겠다!

해서 했는데 또 다른 장벽이 있었습니다. 호스트 OS 에서 TablePlus (MySQL Workbench)로 가상머신에 호스팅 되어있는 MySQL 서버를 접속하려 하니 안되어서…삽질 하다가 찾은 방법들을 정리해서 “Vagrant 로 Ubuntu 18.04 가상머신 구축후 MySQL 8 설치하고 호스트에서 접속하는 방법”을 적어봅니다.

이제 호스트 OS 에서 접속만 하면 됩니다!

  • Host: 127.0.0.1
  • user, password 는 MySQL 에 설정한대로 입력
  • Over SSH 접속 옵션 (MySQL Workbench 에서는 SSL 탭)
  • Server 는 Vagrantfile 에 명시한 VM IP 주소 (전 192.168.56.79 였습니다) , Port 는 22
  • User 는 vagrant, password 는 필요 없음
  • SSH key 는 [가상머신프로젝트]/.vagrant/machines/[가상머신호스트]/virtualbox/private_key

--

--

No responses yet