Explanation
컨테이너 이미지는 여러 층으로 구성되어 있음
그러한 레이어들은 한 번 만들어지고 나면 불변성을 지님. 그렇다면, 불변성은 어떤 의미를 가지는 걸까? 레이어들은 컨테이너가 사용하는 파일 시스템을 만드는 데에 어떻게 사용될까?
Image Layers
각 레이어는 파일 시스템 변화(CRUD)의 집합(set)을 포함하는 이미지
이론상으로의 구조를 살펴보자면 다음과 같음 :
1.
첫번째 레이어 : 기본적인 명령어들과 패키지 매니저들을 추가
2.
두번째 레이어 : 파이썬 런타임과 pip(의존성 관리)를 추가
3.
세번째 레이어 : 앱의 requirements.txt 파일을 복사
4.
네번째 레이어 : 앱의 특정 의존성들을 설치
5.
다섯번째 레이어 : 앱의 소스코드를 복사
이러한 구조는, 이미지들 사이에 재사용이 가능하다는 장점을 가짐. 예를 들어, 또 다른 파이썬 앱을 만들어야하는 경우, layer 구조(layering)를 가지기 때문에, 손쉽게 파이썬 기반의 동일 구조를 구축 가능. 이는 “빠른 빌드 & 스토리지 사용량 및 이미지들을 배포하는 데 필요한 대역폭(bandwith) 감소” 라는 이점을 줌.
위 예시의 이미지 레이어링은 다음과 비슷하다고 말할 수 있음 :
레이어들은 우리가 다른 사람들의 기본 레이어들을 재사용함으로써 빠른 확장이 가능함. 이후 우리는 그저 앱의 데이터들만 추가해주면 됨
Stacking the layers
레이어링은 content-addressable storage & union filesystem을 통해 가능. 작동 방식은 다음과 같음 :
1.
각 레이어를 다운받으면, host filesystem의 자체 디렉토리로 추출됨
2.
이미지로부터 컨테이너를 실행하면, union filesystem이 새롭고 통합된 내용(view)을 만듦으로써 레이어가 쌓인 곳에 추가됨(stacked)
3.
컨테이너가 시작되면, 최상위(root) 디렉토리는 chroot를 이용해 unified 디렉토리의 위치를 최상위 디렉토리로 설정
union filesystem이 생성되면, 이미지 레이어 외에도, 실행중인 컨테이너를 위한 디렉토리가 생성됨. 이는 원본 이미지는 보존하면서 파일시스템 변화를 만들기 위함(불변성). 우리가 동일 underlying 이미지로부터 여러 컨테이너를 실행할 수 있게끔 해줌
Try it out
새 이미지 레이어를 docker container commit 명령어를 통해 수동으로 생성해볼 예정
Create a base image
1.
docker desktop 설치 & 실행
2.
터미널에서, 다음 명령어를 실행해서 새 컨테이너를 시작
docker run --name=base-container -ti ubuntu
Bash
복사
ubuntu라는 이미지를 도커hub에서 가져와서 base-container라는 이름으로 컨테이너 저장 & 컨테이너 실행
이미지를 다운받고 컨테이너가 실행되면, 새 쉘 프롬프트가 나옴. 이는 컨테이너 내에서 실행되는 것임. 다음과 비슷 :
3.
컨테이너 내에서, 다음 명령어를 입력해 Node.js를 설치 :
apt update && apt install -y nodejs
Bash
복사
이제 Node가 컨테이너 내에 설치됨. union filesystem 맥락에서, 이러한 filesystem 변화는 해당 컨테이너에게 고유한(unique) 디렉토리 내에서 발생
4.
Node 명령어가 작동하는 지 확인 :
node -e 'console.log("Hello world!")'
Bash
복사
다음과 같이 잘 작동 :
5.
Node를 설치하면, 이제 새 컨테이너를 만들거나 새 이미지를 만듦으로써 새 이미지 레이어로서 변화 내용을 저장 가능(docker container commit 명령어를 통해). 새 터미널에 다음을 입력 :
docker container commit -m "Add node" base-container node-base
Bash
복사
우리가 첫 컨테이너를 실행할때, 이름을 ‘base-container’로 지정함. 즉 base-container에 새 커밋을 찍고, node-base라고 명명함
6.
docker image history 명령어를 통해 새 이미지 레이러를 확인 :
docker image history node-base
Bash
복사
새로 커밋한 ‘node-base’ 커밋에 대해
7.
실제로 Node가 설치된 이미지인지 확인하기 위해, 새 이미지를 이용해 새 컨테이너를 시작 :
docker run node-base node -e "console.log('Hello again')"
Bash
복사
8.
base 이미지를 생성해봤으니, 지우기 :
docker rm -f base-container
Bash
복사
Base image definition
Build an app image
base 이미지를 생성했으므로, 우리는 이제 추가적인 이미지들을 빌드함으로써 확장 가능
1.
새롭게 생성한 node-base 이미지를 이용해 새 컨테이너를 시작
docker run --name=app-container -ti node-base
Bash
복사
node-base라는 이미지를 도커hub에서 가져와서 app-container라는 이름으로 컨테이너 저장 & 컨테이너 실행
2.
컨테이너 내에서, Node 프로그램을 생성하기 위해 다음 명령어를 입력 :
echo 'console.log("Hello from an app")' > app.js
Bash
복사
Hello from an app 문자열을 app.js 파일의 입력값으로 추가
Node 프로그램이 정상적으로 작동했는지 테스트 :
node app.js
Bash
복사
3.
또 다른 터미널에서, 새 이미지로 컨테이너 변화를 저장하기 위해 다음 명령어를 입력 :
docker container commit -c "CMD node app.js" -m "Add app" app-container sample-app
Bash
복사
sample-app이라는 새 이미지를 생성하고 컨테이너 실행시 수행되는 기본 명령어 구성을 추가
4.
컨테이너 외부 터미널에서, 다음 명령어를 입력해 업데이트된 레이어를 확인 :
docker image history sample-app
Bash
복사
sample-app 이미지의 레이어 확인
5.
마지막으로, 최신 이미지를 이용해 새 컨테이너를 실행. 기본 명령어(default command : node app.js)를 설정했기 때문에, 다음과 같은 명령어 사용 가능
docker run sample-app
Bash
복사
6.
컨테이너 제거 :
docker rm -f app-container
Bash
복사
Next steps
대다수의 이미지 빌드는 docker container commit을 사용하지 않음. 대신, 우리를 위해 위의 단계들을 자동화해주는 Dockerfile을 사용











