Canvas 1 Layer 1

홈브류(Homebrew)를 사용해 맥OS(macOS) 특정 버전의 패키지 설치하기

들어가며

홈브류를 사용하면 맥OSmacOS에서 손쉽게 애플리케이션을 설치할 수 있습니다. 하지만 홈브류는 패키지의 버전 업이 빠른 편이며, 기본적으로 패키지의 최신 버전 설치만을 지원하고 있습니다. 꽤 오래 전에는 versions 명령어를 통해서 구 버전을 확인하고 설치할 수 있었습니다만, 현재는 이 방식을 지원하고 있지 않습니다. 이 글에서는 홈브류를 사용해 특정 버전의 설치 및 사용이 가능한 네 가지 경우에 대해서 알아봅니다.

홈브류에서 구 버전 설치를 지원하는 경우

홈브류에서 구 버전을 별도의 패키지로 관리하고 있는 경우로, 가장 쉬운 케이스입니다.* brew search 명령어로 사용하고자하는 패키지를 검색하면 패키지명 뒤에 @<버전>이 붙어있는 경우가 있습니다. @이 붙어있지 않은 경우가 최신 패키지이고, @이 붙어있는 패키지는 구 버전을 지원하기 위한 패키지입니다. (검색 결과는 편의상 일부 생략하였습니다.)

$ brew search mysql
==> Formulae
mysql ✔  mysql@5.5  mysql@5.6  mysql@5.7

$ brew search node
==> Formulae
node ✔  node@4  node@6  node@8

$ brew search postgresql
==> Formulae
postgresql  postgresql@9.4  postgresql@9.5  postgresql@9.6

이어서 포스트그레SQL의 경우를 살펴보겠지만 구 버전의 설치만 쉬울 뿐, 서버와 실행파일 모두 관리가 필요하기 때문에 버전을 바꿔가면서 사용하는 게 실제로 꽤 번거롭습니다. 이 방법을 사용하기보다는 서버의 포트 설정 등을 변경해 최신 버전과 구 버전 서버를 동시에 실행시켜놓거나, 도커Docker를 사용하면 데이터베이스 서버를 좀 더 쉽게 바꿔가면서 사용할 수 있습니다.

또한 아주 많이 사용되는 패키지가 아닌 경우 홈브류에서는 대부분 구 버전을 지원하지 않으며, 대부분의 경우 특정 메이저 버전의 최신 버전만을 지원한다는 한계가 있습니다.

포스트그레SQLPostgreSQL 최신 버전과 9.6 동시에 사용하기

앞선 예제에서 포스트그레SQLPostgreSQL의 구 버전 패키지가 있는 것을 확인했습니다. 하지만 이 경우 postgresql 최신 버전과 postgresql@9.6 패키지는 2개로 나뉘어져있습니다. 이 두 패키지는 버전만 다를 뿐, 패키지에 속해있는 실행 파일들의 이름들은 대체로 같을 것입니다. 홈브류에서는 switch 명령어를 통해 같은 패키지의 여러 버전이 설치되어있는 경우 사용하고자 하는 패키지를 변경하는 기능을 제공합니다. 하지만 포스트그레SQL의 경우에는 서로 다른 두 개의 패키지가 설치되어버리므로 switch 명령어를 사용할 수 없습니다. 따라서 두 패키지를 번갈아 쓰기 위한 트릭이 필요합니다.

먼저 PostgreSQL 최신 버전 패키지를 설치합니다.

$ brew install postgresql
Updating Homebrew...
==> Downloading https://homebrew.bintray.com/bottles/postgresql-10.4.high_sierra.bottle.tar.gz
---
To have launchd start postgresql now and restart at login:
  brew services start postgresql
Or, if you don't want/need a background service you can just run:
  pg_ctl -D /usr/local/var/postgres start
==> Summary
🍺  /usr/local/Cellar/postgresql/10.4: 3,389 files, 39.5MB

최신 버전 postgres 패키지는 /usr/local/Cellar/postgresql/10.4에 설치됩니다. 설치가 끝나고 출력되는 설명에 따라 서비스를 실행시킵니다.

$ brew services start postgresql

이제 0.0.0.0:5432로 서버에 접속할 수 있습니다. 클라이언트 명령어인 psql 버전도 확인해봅니다.

$ psql --version
psql (PostgreSQL) 10.4

10.4가 설치되어있는 것을 확인할 수 있습니다. 이제 psqlpostgres 데이터베이스에 접속해봅니다.

$ psql postgres
psql (10.4)
Type "help" for help.

postgres=#

서버의 버전은 SELECT version(); 쿼리로 확인할 수 있습니다.

postgres=# SELECT version();
version
------------------------------------------------
 PostgreSQL 10.4 on x86_64-apple-darwin17.5.0...
(1 row)

서버와 클라이언트의 버전이 모두 10.4인 것을 확인할 수 있습니다. 시스템에 10.4 버전을 설치했으니 당연한 일입니다.

이제 앞서 확인한 포스트그레SQL 9.6 버전을 설치해보겠습니다.

$ brew install postgresql@9.6

다시 클라이언트와 서버의 버전을 확인해봅니다.

$ psql --version
psql (PostgreSQL) 10.4

$ psql postgres
postgres=# SELECT version();
version
------------------------------------------------
 PostgreSQL 10.4 on x86_64-apple-darwin17.5.0...
(1 row)

여전히 클라이언트와 서버 모두 10.4입니다. 하나씩 9.6으로 바꿔보겠습니다. 먼저 기존 10.4의 서비스를 종료하고, 9.6 서비스를 실행시켜줍니다.

$ brew services stop postgresql
$ brew services start postgresql@9.6

다시 한 번 클라이언트와 서버의 버전을 확인해봅니다.

$ psql --version
psql (PostgreSQL) 10.4

postgres=# SELECT version();
version
------------------------------------------------
 PostgreSQL 9.6.9 on x86_64-apple-darwin17.5.0...

서버의 버전은 9.6.9인 것을 확인할 수 있습니다. 또한 최신 버전(/usr/local/var/postgres)과 9.6 패키지가 데이터를 저정하는 곳(/usr/local/var/postgresql@9.6)이 다르기 때문에 완전히 다른 서버라고 생각해도 무방합니다. 하지만 여전히 클라이언트는 최신 버전인 10.4를 사용하고 있습니다.

9.6 패키지의 실행 파일을 사용하기 위해서는 홈브류의 link, unlink 기능을 사용해 패키지의 연결을 다시 해줄 필요가 있습니다. 현재는 10.4 패키지가 링크되어있는 상태이므로, 10.4 패키지를 언링크하고 9.6 패키지를 링크해줍니다.

$ brew unlink postgresql
Unlinking /usr/local/Cellar/postgresql/10.4... 377 symlinks removed

$ brew link --force postgresql@9.6
Linking /usr/local/Cellar/postgresql@9.6/9.6.9... 437 symlinks created

이제 클라이언트 버전을 확인해봅니다.

$ psql --version
psql (PostgreSQL) 9.6.9

이제 클라이언트와 서버 모두 9.6.9가 되었습니다.

다시 10.4(최신버전)을 사용하려면 명령어를 반대로 실행해주면됩니다.

$ brew services stop postgresql@9.6
$ brew services start postgresql
$ brew unlink postgresql@9.6
$ brew link --force postgresql

다시 버전을 확인해보면 10.4로 돌아온 것을 확인할 수 있습니다.

$ psql --version
psql (PostgreSQL) 10.4

$ psql postgres
postgres=# SELECT version();
version
------------------------------------------------
 PostgreSQL 10.4 on x86_64-apple-darwin17.5.0...
(1 row)

이 방법은 잘 동작하지만 상당히 번거롭다는 단점이 있습니다.

특정 패키지를 업그레이드하면서 구 버전이 남아있는 경우

두 번째는 특정 패키지를 업그레이드하면서 구 버전이 남아있는 경우입니다. 제가 애용하는 테라폼 패키지를 예로 살펴보겠습니다. 홈브류를 사용해 테라폼Terraform을 단 한 번만 설치했다면 brew info 명령어의 실행 결과가 다음과 비슷할 것입니다.

$ brew info terraform
terraform: stable 0.11.7 (bottled), HEAD
Tool to build, change, and version infrastructure
https://www.terraform.io/
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/terraform.rb
==> Dependencies
Build: go ✘, gox ✘
==> Options
--HEAD
        Install HEAD version

홈브류에서는 해당 패키지가 업그레이드 되었을 때 brew upgrade 명령어로 특정 패키지를 업그레이드할 수 있습니다. 최신 버전이 있다면 해당 패키지의 최신 버전을 다시 설치합니다. 이 때 과거 버전은 그대로 놔두고 새로운 버전을 설치한다는 게 중요한 포인트입니다. 이렇게 업그레이드를 하면서 같은 패키지의 여러 버전이 설치되어있는 경우, brew info를 실행해보면 앞서 확인한 것과는 결과가 조금 다릅니다.

$ brew info terraform
terraform: stable 0.11.7 (bottled), HEAD
Tool to build, change, and version infrastructure
https://www.terraform.io/
Conflicts with:
  tfenv (because tfenv symlinks terraform binaries)
/usr/local/Cellar/terraform/0.11.1 (7 files, 68.4MB)
  Poured from bottle on 2018-01-08 at 09:23:49
/usr/local/Cellar/terraform/0.11.4 (7 files, 80.2MB)
  Poured from bottle on 2018-03-17 at 16:18:29
/usr/local/Cellar/terraform/0.11.5 (7 files, 80.2MB)
  Poured from bottle on 2018-03-27 at 14:46:28
/usr/local/Cellar/terraform/0.11.7 (6 files, 80.2MB) *
  Poured from bottle on 2018-06-24 at 12:47:22
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/terraform.rb
==> Dependencies
Build: go ✘, gox ✘
==> Options
--HEAD
        Install HEAD version

이미 시스템에 있는 구버전들의 목록도 함께 출력됩니다. 현재 활성화된 버전 뒤에 *가 붙어있습니다. /usr/local/Cellar/terraform/ 디렉터리에 이동해서 설치된 전체 목록을 확인해볼 수 있습니다.

$ ls /usr/local/Cellar/terraform/
0.11.1 0.11.4 0.11.5 0.11.7

현재 제 시스템에는 0.11.1, 0.11.4, 0.11.5, 0.11.7 총 4개의 버전이 설치되어있고 최신 버전인 0.11.7이 활성화되어있습니다. 이 경우 switch 명령어를 통해서 패키지의 특정 버전의 바이너리가 실행되도록 설정할 수 있습니다. 0.11.1 버전을 활성화해보겠습니다.

먼저 현재 테라폼 버전을 확인해봅니다.

$ terraform --version
Terraform v0.11.7

v0.11.7이 출력되는 것을 확인할 수 있습니다. 이제 switch 명령어르 테라폼 패키지의 버전을 변경해보겠습니다.

$ brew switch 0.11.1
Cleaning /usr/local/Cellar/terraform/0.11.7
Cleaning /usr/local/Cellar/terraform/0.11.1
Cleaning /usr/local/Cellar/terraform/0.11.4
Cleaning /usr/local/Cellar/terraform/0.11.5
2 links created for /usr/local/Cellar/terraform/0.11.1

$ terrafrom --version
Terraform v0.11.1

Your version of Terraform is out of date! The latest version
is 0.11.7. You can update by downloading from www.terraform.io/downloads.html

v0.11.1이 활성화된 것을 확인할 수 있습니다. 테라폼에서도 0.11.7이 최신 버전이라는 사실을 친절하게 알려줍니다.

switch 기능을 사용하면 이와같이 하나의 패키지에서 여러 버전이 설치되어있을 때 아주 쉽게 패키지의 버전을 변경할 수 있습니다. 하지만 한 가지 문제점이 있습니다. 처음에 다룬 버전에 따라 패키지가 나눠저 있는 경우 홈브류를 통해서 과거 버전을 설치할 수 있었습니다.* 하지만 switch는 하나의 패키지에서 이미 설치된 버전이 존재할 경우에만 사용이 가능합니다. 안타깝게도 brew install을 사용해 과거 버전을 쉽게 설치하는 방법은 없습니다.

* 두 방식의 차이를 이해하는 것이 중요합니다. 앞서 다룬 포스트그레SQL의 경우 두 개의 버전이 서로 다른 패키지로 존재합니다. 하지만 테라폼의 경우는 terraform 패키지가 존재하고 이 아래에 여러 버전들이 존재합니다. 물론 postgresql이나 postgresql@9.6 아래에는 또 다시 여러 개의 버전들이 존재할 수 있습니다. 점점 더 혼란스러워지는 느낌이지만, 패키지 아래에는 여러 버전들이 존재할 수 있다고 이해해두면 좋습니다.

조금 귀찮지만 특정 패키지의 과거 버전을 설치하는 게 불가능한 것은 아닙니다. 다음으로 이 방법에 대해서 알아보겠습니다.

특정 패키지의 구 버전을 레시피 파일로부터 직접 설치하기

홈브류의 패키지는 레시피라는 형식으로 작성되어 홈브류 공식 저장소에서 관리됩니다. 하나의 레시피는 하나의 버전이 정의되기 때문에 홈브류에서는 하나의 패키지당 하나의 버전(일반적으로 최신 버전)만 가지고 있습니다. 예를 들어 테라폼 패키지는 여기에서 최신 레시피를 확인할 수 있습니다. 홈브류에서는 이 레시피 파일을 사용해 패키지를 설치할 수 있습니다. 앞서 제 작업 환경에는 0.11.1, 0.11.4, 0.11.5, 0.11.7 이렇게 네 가지 버전이 설치된 것을 확인해보았습니다. 여기서는 0.11.2 레시피 파일을 찾아서 이 버전을 설치해보겠습니다.

현재 homebrew-core 저장소 커밋이 10만개가 넘어서 깃허브GitHub에서 바로 히스토리를 확인하는 것이 쉽지 않습니다. 적당한 디렉터리에 먼저 homebrew-core를 클론합니다.

$ git clone https://github.com/Homebrew/homebrew-core.git
$ cd homebrew-core

다음 명령어로 Formula/terraform.rb 파일의 이력에서 0.11.2를 찾습니다. 이 명령어는 git의 모든 로그를 탐색하기 때문에 검색 결과가 나오면 ^C로 명령어 실행을 중지합니다.

$ git --no-pager log --pretty=oneline -- Formula/terraform.rb | grep 0.11.2
daa645ea4c0987a5e540508caf399942120872e5 terraform: update 0.11.2 bottle.
b4872192f90923262541de9c2b3f3d8a53447810 terraform 0.11.2

daa645ea으로 0.11.2 버전을 설치해보겠습니다.

깃헙 저장소에서 이 레시피를 다운로드 받을 수 있습니다. https://raw.githubusercontent.com/Homebrew/homebrew-core/<COMMIT_HASH>/Formula/terraform.rb에서 <COMMIT_HASH> 부분을 daa645ea로 수정합니다. 이를 직접 설치하면 충돌이 일어나기 때문에 먼저 brew unlink를 실행하고 설치를 진행합니다.

$ brew unlink terraform
$ brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/daa645ea/Formula/terraform.rb

0.11.2가 설치되었는지 버전을 확인해봅니다.

$ terraform version
Terraform v0.11.2

이 방식으로 설치한 경우에도 terraform 패키지 아래에서 하나의 버전으로 관리됩니다. 따라서 switch 명령어를 사용하면 쉽게 다른 버전으로 변경하는 것이 가능합니다. 다시 최신 버전으로 변경하고 버전을 확인해보겠습니다.

$ brew switch terraform 0.11.7
$ terraform version
Terraform v0.11.7

구 버전 레시피의 경우 정상적으로 동작하지 않는 경우가 있습니다. 이런 경우 직접 파일을 편집하는 등의 추가적인 작업이 필요합니다. 구 버전 레시피를 찾고 수정해야하는 번거로움이 있지만 이 방식을 사용하면 홈브류를 통해서 구 버전 패키지를 설치 및 관리하는 것이 가능합니다.

특정 패키지의 구 버전을 직접 설치하기

마지막 방법은 asbubam 님께 배운 방법으로 특정 패키지의 구 버전을 홈브류를 거치지 않고 직접 설치하는 방법입니다. 홈브류 팁 앤 트릭 문서에는 홈브류 없이 특정 패키지를 설치하는 간단한 팁을 소개하고 있습니다.

$ ./configure --prefix=/usr/local/Cellar/foo/1.2 && make && make install && brew link foo

구체적인 사례는 아닙니다만 소스 코드에서 직접 빌드한 내용을 foo 패키지의 1.2 디렉터리 아래에 설치하고 brew link를 통해서 실행 파일을 연결하는 방법입니다. 테라폼의 경우에는 과거 버전의 빌드된 바이너리가 제공되므로 훨씬 간단히 구 버전을 설치하는 것이 가능합니다. 이 방법으로 0.11.3 버전을 설치해보겠습니다. 테라폼에서는 공식적으로 릴리즈 페이지에서 구 버전의 바이너리 파일을 제공하고 있습니다. 맥에서는 darwin_amd64 타입을 사용합니다.

$ wget https://releases.hashicorp.com/terraform/0.11.3/terraform_0.11.3_darwin_amd64.zip
$ unzip terraform_0.11.3_darwin_amd64.zip

압축을 풀면 terraform 파일이 하나 생성됩니다.

$ ./terraform --version
Terraform v0.11.3

현재 디렉터리에서 바로 실행해보면 이 바이너리가 테라폼 0.11.3 파일이라는 것을 확인할 수 있습니다. 이 파일을 홈브류에서 관리하는 방식으로 추가만 하면 됩니다. /usr/local/Cellar/ 아래에 적절히 디렉터리를 만들고 바이너리 파일을 복사해줍니다.

$ mkdir -p /usr/local/Cellar/terraform/0.11.3/bin
$ mv ./terraform /usr/local/Cellar/terraform/0.11.3/bin

홈브류는 패키지의 버전들을 디렉터리의 유무로 확인합니다. 따라서 이제 switch 명령어를 실행해보면 0.11.3이 추가된 것을 확인할 수 있습니다.

$ brew switch terraform
Error: Usage: brew switch <formula> <version>
terraform installed versions: 0.11.1, 0.11.2, 0.11.3, 0.11.4, 0.11.5, 0.11.7

실제로 작동하는 지 0.11.3으로 변경하고 버전을 확인해봅니다.

$ brew switch terraform 0.11.3
$ terraform --version
Terraform v0.11.3

정상적으로 0.11.3이 실행되는 것을 확인할 수 있습니다. 🎉

마치며

어떤 애플리케이션의 최신 버전이 아닌 특정 버전을 사용해야하는 경우는 의외로 자주 발생합니다. 홈브류는 맥OS의 패키지 관리자로 실질적 표준의 자리를 점하고 있습니다만, 특정 버전의 패키지를 설치하거나 여러 버전을 설치하는 게 생각만큼 간단하게 되지는 않습니다. 하지만 홈브류가 패키지를 관리하는 기본적인 원리만 이해한다면 충분히 시도해볼만한 일입니다.

더 읽을 거리