Running Your First Container
한국어 원문으로 표시합니다.
이 실습은 진짜 VM 에서 돕니다
이 상자는 파드가 아니라 KubeVirt 가 띄운 가상머신입니다. 리눅스 커널이
따로 돌고 systemd 가 실제로 서비스를 관리하며, docker 는 흉내가 아니라
진짜 도커 엔진입니다. docker run 으로 띄운 컨테이너는 실제로 프로세스가
되고 docker exec 도 docker logs 도 그대로 동작합니다.
예전에는 이 실습이 파드 안에서 돌았습니다. 커널 권한을 전부 내려놓은 상자라 컨테이너를 띄우는 단계가 막혀 있었고, 그래서 이미지 아카이브를 직접 풀어 보는 우회로 배웠습니다. 이제 우회가 필요 없습니다.
알아 둘 것이 둘 있습니다.
- 처음 뜨는 데 1분 남짓 걸립니다. VM 이 부팅하고 도커를 설치하기 때문입니다. 파드 실습(보통 40초)보다 느립니다.
- 브라우저 미리보기가 없습니다. VM 으로 들어오는 연결은 채점 포트
하나만 열려 있습니다. 웹 서버를 띄웠다면 VM 안에서
curl로 확인하세요.
목표
이미지와 컨테이너를 손으로 다루면서, 태그가 이미지를 복사하지 않는다는 것과 컨테이너 안팎이 서로 다른 파일 트리를 본다는 것을 직접 확인합니다.
왜 중요한가
컨테이너를 처음 만나면 대부분 명령어를 외우려 듭니다. 그런데 실무에서 막히는 지점은 명령어가 아니라 모델입니다. "이미지를 지웠는데 컨테이너가 살아 있다", "태그를 바꿨는데 용량이 안 줄었다", "컨테이너 안에서는 파일이 있는데 호스트에는 없다" — 전부 이미지는 읽기 전용 레이어 더미이고 컨테이너는 그 위의 쓰기 레이어 + 프로세스라는 한 문장에서 설명됩니다. 그래서 이 실습은 명령을 익히는 것이 아니라 그 문장을 눈으로 확인하는 과정입니다.
단계
/root/dk1디렉터리를 만들고, 이 상자에서 쓸 수 있는 이미지 목록을/root/dk1/images.txt로 저장합니다. 저장소와 태그가 함께 보여야 합니다.docker images는 이 상자에서 동작하지 않습니다. 대신/opt/images/*.tar안의index.json에서.manifests[0].annotations["org.opencontainers.image.ref.name"]를 읽으면docker.io/library/alpine:3.20같은 이름:태그가 그대로 나옵니다 —docker images의 Repository·Tag 두 열이 어디에서 오는지를 한 겹 아래에서 보는 셈입니다.alpine:3.20이미지로dk-hello라는 이름의 컨테이너를 만들어hello-labhub를 출력하게 하고, 종료 후에도 컨테이너를 남겨 둡니다.nginx:1.27-alpine을dk-web이라는 이름으로 백그라운드 실행합니다.nginx:1.27-alpine컨테이너가 보는/etc/os-release를 읽어/root/dk1/web-os.txt로 저장합니다.docker exec dk-web cat /etc/os-release로 읽습니다. 이 VM 의/etc/os-release를 그냥 읽으면 우분투가 나와 실패합니다 — 그 차이가 곧 마운트 네임스페이스가 하는 일입니다.dk-web의 컨테이너 IP 주소를 알아내/root/dk1/web-ip.txt에 IPv4 주소 한 줄만 저장합니다.alpine:3.20에labhub/base:v1이라는 이름을 추가로 붙입니다.dk-hello컨테이너를 삭제합니다.dk-web은 그대로 둡니다./root/dk1/report.txt에 아래 세 줄을 실제 값으로 채워 넣습니다.
image=<dk-web 이 쓰는 이미지 이름:태그>
container=dk-web
state=<dk-web 의 현재 상태>
참고
docker images --format '{{.Repository}}:{{.Tag}}'로 원하는 열만 뽑을 수 있습니다.docker inspect <이름> | jq -r '.[0].State.Status'처럼 JSON 을 직접 파고드는 편이 안전합니다.- 흔한 실수 1: 2단계에서
--rm을 붙이면 컨테이너가 즉시 사라져 채점할 것이 없습니다. - 흔한 실수 2: 4단계에서 호스트의
/etc/os-release를 읽으면 우분투가 나옵니다. 컨테이너 안에서 읽어야 합니다.
이미지 목록 저장하기
/root/dk1 디렉터리를 만들고, 이 상자에서 쓸 수 있는 이미지 목록을 /root/dk1/images.txt 로 저장합니다. 저장소와 태그가 함께 보여야 합니다.
docker images 는 이 상자에서 동작하지 않습니다. 대신 /opt/images/*.tar 안의 index.json 에서 .manifests[0].annotations["org.opencontainers.image.ref.name"] 를 읽으면 docker.io/library/alpine:3.20 같은 이름:태그가 그대로 나옵니다 — docker images 의 Repository·Tag 두 열이 어디에서 오는지를 한 겹 아래에서 보는 셈입니다.
이미지 목록을 보여 주는 하위 명령이 있습니다. 출력을 화면에서 읽는 데 그치지 말고 리다이렉션으로 파일에 남기세요. 저장소 이름만이 아니라 태그 열까지 함께 남아야 합니다.
한 번 실행하고 끝나는 컨테이너
alpine:3.20 이미지로 dk-hello 라는 이름의 컨테이너를 만들어 hello-labhub 를 출력하게 하고, 종료 후에도 컨테이너를 남겨 둡니다.
이름을 붙여 두면 나중에 찾기 쉽습니다. --rm 을 붙이면 끝나자마자 지워져서 채점할 대상이 사라진다는 점에 주의하세요.
백그라운드로 계속 도는 컨테이너
nginx:1.27-alpine 을 dk-web 이라는 이름으로 백그라운드 실행합니다.
포그라운드로 띄우면 터미널이 붙잡힙니다. 컨테이너를 분리해서 띄우는 플래그가 있습니다. nginx 는 종료되지 않고 계속 떠 있는 것이 정상입니다.
실행 중인 컨테이너 안에서 명령 돌리기
nginx:1.27-alpine 컨테이너가 보는 /etc/os-release 를 읽어 /root/dk1/web-os.txt 로 저장합니다.
docker exec dk-web cat /etc/os-release 로 읽습니다. 이 VM 의 /etc/os-release 를 그냥 읽으면 우분투가 나와 실패합니다 — 그 차이가 곧 마운트 네임스페이스가 하는 일입니다.
호스트에서 /etc/os-release 를 읽으면 우분투가 나옵니다. 컨테이너의 마운트 네임스페이스 안에서 읽어야 알파인이 나옵니다.
컨테이너의 IP 알아내기
dk-web 의 컨테이너 IP 주소를 알아내 /root/dk1/web-ip.txt 에 IPv4 주소 한 줄만 저장합니다.
inspect 출력은 JSON 입니다. jq 로 파고들거나 --format 템플릿을 쓰세요. 파일에는 IP 주소만 남겨야 합니다.
이미지에 다른 이름 붙이기
alpine:3.20 에 labhub/base:v1 이라는 이름을 추가로 붙입니다.
태그는 이미지를 복사하지 않습니다. 새 이름을 붙인 뒤 두 이름의 이미지 ID 를 비교해 보세요.
끝난 컨테이너만 정리하기
dk-hello 컨테이너를 삭제합니다. dk-web 은 그대로 둡니다.
종료된 컨테이너도 쓰기 레이어를 붙잡고 있습니다. 실행 중인 것은 남기고 끝난 것만 지워야 합니다.
현재 상태를 보고서로
/root/dk1/report.txt 에 아래 세 줄을 실제 값으로 채워 넣습니다.
세 줄 모두 실제 inspect 값과 대조합니다. 추측해서 적지 말고 명령으로 확인한 값을 쓰세요.