Declare a Stack and Check It Against Reality
한국어 원문으로 표시합니다.
이 실습은 진짜 VM 에서 돕니다
이 상자는 파드가 아니라 KubeVirt 가 띄운 가상머신입니다. 리눅스 커널이
따로 돌고 systemd 가 실제로 서비스를 관리하며, docker 는 흉내가 아니라
진짜 도커 엔진입니다. docker run 으로 띄운 컨테이너는 실제로 프로세스가
되고 docker exec 도 docker logs 도 그대로 동작합니다.
예전에는 이 실습이 파드 안에서 돌았습니다. 커널 권한을 전부 내려놓은 상자라 컨테이너를 띄우는 단계가 막혀 있었고, 그래서 이미지 아카이브를 직접 풀어 보는 우회로 배웠습니다. 이제 우회가 필요 없습니다.
알아 둘 것이 둘 있습니다.
- 처음 뜨는 데 1분 남짓 걸립니다. VM 이 부팅하고 도커를 설치하기 때문입니다. 파드 실습(보통 40초)보다 느립니다.
- 브라우저 미리보기가 없습니다. VM 으로 들어오는 연결은 채점 포트
하나만 열려 있습니다. 웹 서버를 띄웠다면 VM 안에서
curl로 확인하세요.
목표
두 서비스로 이루어진 스택을 Compose 파일로 선언하고, 같은 스택을 손으로도 띄운 뒤, 선언한 값과 실제 값이 정확히 일치하는지 대조합니다.
왜 중요한가
Compose 를 "여러 컨테이너를 한 번에 띄우는 도구"로만 이해하면 절반만 얻습니다. 진짜 가치는 스택의 모양이 파일에 적혀 저장소에 남는다는 것입니다. 그리고 이 가치는 파일과 현실이 일치할 때만 성립합니다. 누군가 손으로 컨테이너를 고치는 순간 파일은 문서가 아니라 거짓말이 되고, 그 거짓말은 다음 배포 때까지 아무도 모릅니다. 그래서 이 실습의 마지막 단계는 새 기능을 만드는 것이 아니라 대조입니다. 선언형 도구를 쓰는 팀이 반드시 갖춰야 할 습관이 여기 있습니다.
단계
/root/ops3/compose.yaml 을 아래 구조로 작성합니다. 들여쓰기는 2칸이고,
최상위 키(services:, volumes:, networks:)는 반드시 줄 맨 앞에서
시작해야 합니다.
- 최상위에
services:를 두고 그 아래web:과cache:두 서비스를 들여쓰기 2칸으로 선언합니다. web의image는nginx:1.27-alpine,cache의image는alpine:3.20으로 하고,cache에는 계속 실행되도록command를 함께 적습니다.- 최상위에
networks:를 두고 그 아래appnet:을 선언한 뒤, 두 서비스 모두networks:목록에- appnet을 넣습니다. web에ports:를 두고"127.0.0.1:8081:80"을 넣습니다.cache에는ports를 두지 않습니다.- 최상위에
volumes:를 두고webdata:를 선언한 뒤,web의volumes:에webdata:/usr/share/nginx/html을 넣습니다. cache에environment:로CACHE_TTL값60을 넣고,web에depends_on:으로- cache를 넣습니다.- 같은 스택을 손으로 띄웁니다. 네트워크 이름은
ops3net, 컨테이너 이름은ops3-web(nginx:1.27-alpine,127.0.0.1:8081:80퍼블리싱)과ops3-cache(alpine:3.20, 환경변수CACHE_TTL=60)이며 둘 다ops3net에 붙입니다. - 이 단계는 새로 만들 것이 없습니다. 6단계까지의 선언과 7단계의 실제 컨테이너가 이미지·포트·환경변수 세 항목에서 정확히 일치하는지 확인합니다.
참고
- 최상위 키 순서는
services:→volumes:→networks:로 두면 읽기 쉽습니다. - 이 실습에서 8단계 채점은 compose 파일을 파싱해 얻은 값과
docker inspect값을 직접 비교합니다. - 흔한 실수 1: 서비스 이름을 들여쓰기 4칸으로 두면 구조가 달라집니다. 정확히 2칸입니다.
- 흔한 실수 2: 7단계에서 이미지 태그를
nginx:alpine처럼 다르게 쓰면 8단계 대조에서 어긋납니다.
서비스 두 개 선언하기
최상위에 services: 를 두고 그 아래 web: 과 cache: 두 서비스를 들여쓰기 2칸으로 선언합니다.
최상위 services 아래에 서비스 이름을 들여쓰기 2칸으로 둡니다. 들여쓰기가 어긋나면 파일 전체의 의미가 바뀝니다.
이미지와 명령 지정하기
web 의 image 는 nginx:1.27-alpine, cache 의 image 는 alpine:3.20 으로 하고, cache 에는 계속 실행되도록 command 를 함께 적습니다.
alpine 은 기본 명령이 즉시 끝나므로 계속 도는 command 를 함께 적어야 합니다.
공용 네트워크 선언하기
최상위에 networks: 를 두고 그 아래 appnet: 을 선언한 뒤, 두 서비스 모두 networks: 목록에 - appnet 을 넣습니다.
최상위에 networks 를 선언하고 각 서비스에서 그 이름을 참조합니다. 두 곳 모두 필요합니다.
포트는 루프백에만
web 에 ports: 를 두고 "127.0.0.1:8081:80" 을 넣습니다. cache 에는 ports 를 두지 않습니다.
포트 문자열에 바인딩 주소를 앞에 붙일 수 있습니다. 내부 통신만 하는 서비스에는 ports 를 쓰지 않습니다.
이름 있는 볼륨 선언하기
최상위에 volumes: 를 두고 webdata: 를 선언한 뒤, web 의 volumes: 에 webdata:/usr/share/nginx/html 을 넣습니다.
최상위 volumes 에 이름을 선언하고 서비스에서 대상 경로와 함께 씁니다.
환경변수와 기동 순서
cache 에 environment: 로 CACHE_TTL 값 60 을 넣고, web 에 depends_on: 으로 - cache 를 넣습니다.
depends_on 은 순서만 보장하지 준비 상태를 보장하지 않는다는 점을 기억하세요.
같은 스택을 손으로 띄우기
같은 스택을 손으로 띄웁니다. 네트워크 이름은 ops3net, 컨테이너 이름은 ops3-web(nginx:1.27-alpine, 127.0.0.1:8081:80 퍼블리싱)과 ops3-cache(alpine:3.20, 환경변수 CACHE_TTL=60)이며 둘 다 ops3net 에 붙입니다.
네트워크를 먼저 만들고 컨테이너를 붙입니다. 선언 파일에 적은 값과 정확히 같은 값을 쓰세요.
선언과 실제 대조하기
이 단계는 새로 만들 것이 없습니다. 6단계까지의 선언과 7단계의 실제 컨테이너가 이미지·포트·환경변수 세 항목에서 정확히 일치하는지 확인합니다.
채점은 compose 파일에서 읽은 값과 실제 컨테이너의 inspect 값을 직접 비교합니다. 한 글자라도 다르면 어긋난 것입니다.