여러 이미지에서 공통으로 사용하는 라이브러리가 있습니다. 그래서 base이미지를 하나 만들어 두고 같이 공유해서 사용하고 있습니다.
이렇게 했을 때, 장점은 이미지를 만들 때, 이미 만들어진 공통으로 사용하는 이미지에 라이브러리가 포함되어 있기 때문에
-> 변경사항을 관리할 수 있습니다. base이미지의 버전 관리만 잘한다면, 어떤 이미지에 어떤 버전의 라이브러리가 들어있는지 쉽게 알 수 있고, 추적이 용이해집니다.
-> 그리고 base 이미지는 한번만 빌드하고 공유하기 때문에 이미지 빌드 시간이 줄어듭니다.
하지만, 라이브러리를 이미지에 포함할 경우, 단점도 있습니다.
-> 이미지 내에 라이브러리를 포함하기 때문에 이미지 사이즈가 커집니다.
-> 라이브러리가 변경되면, 해당 라이브러리를 사용하는 모든 이미지를 다시 만들어줘야 합니다.
서비스가 안정화 되고, 공통 라이브러리의 변경이 적다면, 장점이 많은 관리 방법입니다. 물론 이미지 사이즈가 커지는 문제가 있지만, base이미지의 레이어를 공유하기에 실제 물리적인 사이즈가 기하급수로 증가하지는 않습니다.
하지만, 제가 지금 맞닥드린 상황은 개발이 막 진행되는 상태이고, 이런 때는 공통으로 사용되는 라이브러리가 자주 변경됩니다. 그래서 전체 이미지를 새로 빌드해야 하는 상황이 자주 발생합니다. 전체 이미지를 다시 빌드하는 것을 피해보고자 개별 이미지에 라이브러리를 포함하는 것은 더 큰 문제를 야기할 수 있습니다. 어떤 이미지에 어떤 라이브러리가 포함되었는지 알기 힘들뿐더러, 공유되는 이미지 레이어가 없기 때문에 전체 이미지는 더 많은 공간을 차지하게 됩니다.
그래서 전체 이미지를 다시 빌드하지 않기 위해 이런 가정을 해봤습니다.
1. 만약 라이브러리를 볼륨으로 설정해서 공유하면 어떨까?
2. 그리고 심볼릭 링크로 볼륨을 걸어 형상관리까지 해보면 어떨까?
1번 가정은 어렵지 않게 실현 시킬 수 있었습니다. 그리고 이제는 공통 라이브러리 때문에 이미지를 다시 빌드하지 않아도 되는 장점이 생기고, 실제 사용하는 라이브러리도 즉시 판별할 수 있는 장점도 생겼습니다. 그리고 무엇보다 빌드된 이미지 사이즈가 절반으로 줄었습니다. ( 사용하던 이미지 중 가장 큰 변화를 보인 이미지는 2.2GB에서 1.2GB로 크기가 줄었습니다. )
하지만 여전히 불편한 점이 존재했습니다. 공통 라이브러리가 변경될 때마다, 파일을 복사해줘야 하는 점이죠. 물론 복사가 어려운 건 아니지만, 볼륨에 있는 라이브러리는 버전이 제거된 라이브러리 명을 사용해야 했습니다.
A-1.0.1.jar ==> A.jar
B-2.2.1.jar ==> B.jar
그래서 볼륨에 무언가 표시해줄 장치가 필요했습니다. 처음에는 볼륨에 version 파일을 만들어 관리했는데, 바쁘다보면 version파일을 고치는 것을 놓칠 때가 종종 생기고, 그것 때문에 문제가 되는 상황이 몇 번 생겼습니다.
그래서 2번 가정을 했습니다. 실제 원본이 되는 파일을 정해진 곳에 두고, 적용할 라이브러리를 symbolic Link로 연결해 두면 바로 확인할 수 있지 않을까? 라고 하며 시도해봤습니다.
다음과 같이 볼륨을 가진 컨테이너를 구동합니다.
# Dockerfile ( my-image:latest )
FROM ubuntu:20.04
RUN mkdir container-volume
CMD tail -f /dev/null
# docker-compose.yml
version: '3'
services:
app:
image: my-image:latest
volumes:
- ./host_volume:/container_volume
그리고 원본 파일을 real_files 폴더에 만듭니다. A.txt와 B.txt를 사용하는 공통 라이브러리라고 가정합니다.
$ mkdir real_files
$ cd real_files
$ echo "A Lib" > A.txt
$ echo "B Lib" > B.txt
그리고 host_volume에 symbolic Link를 걸어줍니다.
$ ln -s $PWD/A.txt ../host_volume/A.txt
$ ln -s $PWD/B.txt ../host_volume/B.txt
그리고 host_volume을 확인해보면 링크가 잘 걸려있는 것을 볼 수 있습니다.
이제 컨테이너를 실행하고 확인해보면,
컨테이너 볼륨에는 파일이 보이지만, 파일을 사용할 수는 없었습니다. Symbolic 링크가 걸려있기는 하지만, host의 경로가 걸려있기 때문에 컨테이너에서는 사용할 수 없는 상태였습니다. 이렇게는 사용할 수 없었습니다.
그러면, 파일을 symbolic Link로 걸지 않고, 폴더를 링크로 걸면 어떨까요?
$ ln -s $PWD/real_files host_volume/real_files
이제 아까 만든 A.txt, B.txt 외에도, A.txt, B.txt를 담고 있는 폴더도 링크로 걸렸습니다. 이제 다시 컨테이너를 구동해보면
안타깝지만 여전히 host의 경로를 링크로 가리키고 있는 것을 알 수 있었습니다.
그리고 나서 좀 더 찾아보니, 이미 저 같은 시도를 많이 했고, 결론은 안된다라는 걸 알 수 있었습니다.
그래서 심볼릭 링크 대신 docker-compose.yml에 볼륨 폴더를 다음과 같이 지정하여 불편함은 피해 가고 있습니다.
# docker-compose.yml
version: '3'
services:
app:
image: my-image:latest
volumes:
- ./host_lib_v1:/container_volume
# - ./host_lib_v2:/container_volume
결론 적으로, Docker 볼륨으로 symbolic link는 사용할 수 없고, 심볼릭 링크처럼 직관적으로 표시되지는 않지만, 호스트의 볼륨 폴더를 변경하여 마운트 함으로 써, docker inpsect 같은 명령으로 또는 docker-compose.yml을 확인함으로써 확인 가능하니, 아쉽지만 제가 풀고 싶었던 문제들은 해결한 셈입니다.