[작성중] Dockerfile 작성하기 (example : 18.04 systemd container)
안녕하세요? 도정진입니다. 이번에는 Dockerfile 을 작성하는 방법에 대해서 알아보겠습니다.
그냥 제가 쓸 컨테이너를 생성하거나, 배포용 기능 컨테이너를 배포할 때 사용합니다.
1. 개념 설명
기본적으로 base 로 하는 container 들은 하기와 같습니다.
ubuntu / debian / alpine 등을 사용합니다.
실제로 docker 에는 base image 와 dockerfile 로 구성됩니다. base image 는 말 그대로 베이스 이미지이며, 데비안 계열에서는 debbootstrap 으로 생성하여 tar.gz 로 압축을 하는 형태입니다.
https://docs.docker.com/develop/develop-images/baseimages/
한편으론, 프로그램을 빌드하여 필요한 파일만 넣어서 베이스 이미지화 하면 컨테이너 사이즈를 매우 줄일 수 있을 것입니다. --> 컨테이너POD를 오케스트레이션 한다고 할 경우, 아마도 컨테이너가 생성되고 죽는 과정에서 IO를 많이 줄일 수 있을 것입니다.
base image 부분이 일단 제일 하위 레이어이며, 변경이 되지 않는 레이어입니다. 이 상태에서 Dockerfile 을 통해 레이어를 차근 차근 쌓아나간다고 보면 됩니다.
Dockerfile 의 명령들을 하나 하나 실행할 때마다, 레이어가 생기는 구조이고, 이는 그래프 드라이버를 통해 (모듈은 overlayfs) 등으로 합쳐집니다.
즉, 우리가 이미지를 받을 때, 여러 레이어가 받아지고 실제로는 합쳐져서 동작합니다.
예시로 하나의 컨테이너를 inspect 해보면 하기와 같이 나옵니다.
"GraphDriver": { "Data": { "LowerDir": "/DATA/docker/overlay2/c43447979d8e632f1fcb8f8c10900f21330e49ff047e621978c2828153e8aad6-init/diff:/DATA/docker/overlay2/11525354ee0271a9727d319fa1811072a21824a672b1e669a51cd042ea92f650/diff:/DATA/docker/overlay2/72635e150e32193b4b84e23aebb9e6562debfd95c526d2744b7f8b08a1322e07/diff:/DATA/docker/overlay2/835a61c8f10dcc0f109f1e43ba8568411621bb12662fbae772ee3fe12f0e1feb/diff:/DATA/docker/overlay2/9ceab1d93a11b1990a360965f01f43034a4f61f1bb7b2420a90906cd8e8e8ae7/diff", "MergedDir": "/DATA/docker/overlay2/c43447979d8e632f1fcb8f8c10900f21330e49ff047e621978c2828153e8aad6/merged", "UpperDir": "/DATA/docker/overlay2/c43447979d8e632f1fcb8f8c10900f21330e49ff047e621978c2828153e8aad6/diff", "WorkDir": "/DATA/docker/overlay2/c43447979d8e632f1fcb8f8c10900f21330e49ff047e621978c2828153e8aad6/work" }, "Name": "overlay2" }, |
상기를 확인하면, overlay2 드라이버 구조가 나옵니다. 대략적으로 개념은 하기와 같습니다.
(출처 : https://blog.naver.com/alice_k106/221530340759)
이때,
lower : RO 마운트의 최 하위 경로
upper : RW 마운트의 최 상위 경로
merged : 사용자가 작업하는 경로
즉, merged 에서 사용자가 파일을 삭제하거나 변경하면, upper 경로에 변경이 생깁니다.
이는 이전에 구글 드라이브 마운트 관련하여 unionfs 와 비슷한 구조로 보시면 되고, 그때의 구성은 fuse 였으나, 이번에는 overlayfs 라는 것이 조금 차이이며, 물론 개념 차이도 조금 발생하겠지만 거의 비슷한 개념으로 보시면 됩니다.
그리고 실제로 rootfs 는 하기 hash 값을 갖는 이미지들이 합쳐져 구성이 됩니다.
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:96eda0f553ba9988a216cea7cf016d18d5f036677d411883b642c4c8c70e301b",
"sha256:bd95983a8d99e89ec7c7558839a72a79e92ce8c5a6697ad704e341d0d3c43cd5",
"sha256:293b479c17a5448de0814a3c614ac15a0d192a7c2c56f53478f6e3d5cc5cb345",
"sha256:fa1693d66d0b743e6ef621392026f411dad99750ec16926ffd78104a82a123e7",
"sha256:ff760649a0bee395d688feba3d0a3fcd42266faa07ca2f084bcbf5ccedbfec4e",
"sha256:cdcdd1754d21ca27cabdf6ead69b195c2895fcf47c64a1e505fe6123c1f0ca38",
"sha256:5cd323a12c082d83da229178fd4a15ac996b58c18e6086c246f6b3a31b4db96c"
]
},
|
이런 생각을 할 수도 있습니다.
한 rootfs (base image) 를 만드는데 왜 저렇게 쪼개져 있으면 좋나?
쪼개져 있으면 좋은 부분이, 동일 베이스 이미지로 조금만 다른 이미지를 만들어 낼 때,
이때 조금만 다른 이미지라는 것은 특정 레이어 하나에 기록되어 있으면, 나머지는 동일함으로 동일한 부분에 대해서는 한개의 파일로 사용이 가능하게 됩니다.
결국에 용량에 대한 이점이 생기는 것입니다.
이전에 docker 이미지에 대한 rootfs 를 뽑아내는 스크립트를 작성한 적이 있습니다.
https://blog.djjproject.com/626
--> 각 레이어 tar.gz 파일을 한 폴더에 풀어서 합치는 내용입니다.
3. Dockerfile
특정 base 이미지에서 레이어를 쌓아 수정된 이미지를 생성할 때 사용합니다.
bash 스크립트와 조금 차이가 있으며, 대부분 사용하는 커맨드는 하기와 같습니다.