비유하여 확인
→ 이미지(Image) = 라면 레시피 + 라면 봉지
→ 컨테이너(Container) = 실제로 끓인 라면 그릇
→ 같은 이미지를 가지고 여러 그릇(컨테이너)을 막 찍어낼 수 있음
→ 마음에 안 들면 컨테이너는 그냥 버리고, 이미지만 남겨두면 됨
기억하고 갈 것
→ 이미지(Image): 컨테이너를 만들기 위한 템플릿
→ 컨테이너(Container): 실제로 실행 중인 하나의 “프로그램 + 환경”
→ 레지스트리(Registry): 이미지를 저장해둔 창고 (예: Docker Hub)
→ Dockerfile: 이미지를 만드는 레시피(나중에 할 거)



docker --version
docker run hello-world
docker run --name my-nginx -d -p 8080:80 nginx
→ allow 클릭
→ download 완료되면 목록에 하나더 뜸http://localhost:8080
docker ps

docker stop my-nginx
docker start my-nginx
docker ps -a

docker logs my-nginx

"이제 컨테이너 = 작은 리눅스"
docker exec -it my-nginx bash
이 상태로 확인해보기
ls /
cd /usr/share/nginx/html
ls
cat index.html
exit

이제 브라우저 새로고침
HELLO FROM CONTAINER ⭕
HELLO FROM CONTAINER ⭕
docker stop my-nginxdocker rm my-nginx
2. 같은 이미지로 새 컨테이너 생성
3. 브라우저 재접속
원하는 디렉토리로 이동한 후 해당 명령어 실행
mkdir docker-python-app
cd docker-python-app

app.py 파일 생성
nano app.py
내용 붙여넣기
from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(b"<h1>Hello from Docker Image</h1>")
HTTPServer(("0.0.0.0", 8000), Handler).serve_forever()

동일한 디렉토리에 Dockerfile 생성
nano Dockerfile
내용 붙여넣기
FROM python:3.11-slim
WORKDIR /app
COPY app.py .
EXPOSE 8000
CMD ["python", "app.py"]

중요 개념
→ FROM : 실행 환경
→ COPY : 코드를 이미지 안으로 넣음
→ CMD : 컨테이너 시작 시 실행할 명령
이미지 빌드하기
docker build -t my-python-app .

명령어 의미
→ . (온점) : 현재 디렉토리 기준
→ my-phthon-app : 내가 만든 이미지 이름
docker run -d -p 9000:8000 --name python-app my-python-app
http://localhost:9000
docker stop python-appdocker rm python-app
docker run -d -p 9000:8000 --name python-app my-python-app
→ 동일한 것 확인 가능docker stop python-app 2>/dev/null || truedocker rm python-app 2>/dev/null || true
docker stop python-app 2>/dev/null || true
└─────①─────┘ └──②──┘ └─③─┘
① python-app 컨테이너를 중지
문제 : 컨테이너가 이미 없으면 에러 발생 + exit code ≠ 0
② 에러 메시지 숨기기 - 에러 출력(stderr)을 쓰레기통(/dev/null)으로 버려라
기본 개념
0 : 표준 입력 (stdin)
1 : 표준 출력 (stdout)
2 : 표준 에러 (stderr)
③ 실패해도 성공한 척하기 - docker stop 실패해도 true로 최종 결과를 성공으로 만들자
쉘에서 : A || B
A가 실패(exit code ≠ 0) 하면
B를 실행
결론적으로
python-app 컨테이너를 중지하되, 해당 컨테이너가 없어서 에러가 나도
에러 메시지는 표시하지말고 명령 전체는 실패로 취급하지 마라
docker run -it --name vol-test-no python:3.11-slim bash
mkdir -p /datadate > /data/created.txtcat /data/created.txtexit
docker rm vol-test-no
docker run -it --name vol-test-no python:3.11-slim bash
cat /data/created.txt
docker volume create mydatadocker volume ls | grep mydata
docker run -it --name vol-test-yes -v mydata:/data python:3.11-slim bash
date > /data/created.txtcat /data/created.txtexit
docker rm vol-test-yes
docker run -it --name vol-test-yes -v mydata:/data python:3.11-slim bashcat /data/created.txtexit
docker network create app-net
docker network ls | grep app-net

docker run -d --name net-nginx --network app-net nginx

docker run -it --rm --network app-net curlimages/curl:8.10.1 curl -s http://net-nginx | head


cat > requirements.txt << 'EOF'
redis==5.0.8`
EOF

cat > app.py << 'EOF'
from http.server import BaseHTTPRequestHandler, HTTPServer
import os
import redis
REDIS_HOST = os.getenv("REDIS_HOST", "redis")
REDIS_PORT = int(os.getenv("REDIS_PORT", "6379"))
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True)
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
# 카운터 증가
count = r.incr("hits")
self.send_response(200)
self.send_header("Content-type", "text/html; charset=utf-8")
self.end_headers()
body = f"""
<h1>Docker Compose: Web + Redis</h1>
<p>Redis Host: {REDIS_HOST}:{REDIS_PORT}</p>
<p>Hits (stored in Redis): <b>{count}</b></p>
"""
self.wfile.write(body.encode("utf-8"))
HTTPServer(("0.0.0.0", 8000), Handler).serve_forever()
EOF

cat > Dockerfile << 'EOF'
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8000
CMD ["python", "app.py"]
EOF
volumes: → redis 데이터가 컨테이너 삭제 후에도 유지

cat > docker-compose.yml << 'EOF'
services:
web:
build: .
container_name: compose-web
ports:
- "9000:8000"
environment:
REDIS_HOST: redis
REDIS_PORT: "6379"
depends_on:
- redis
redis:
image: redis:7-alpine
container_name: compose-redis
volumes:
- redis-data:/data
volumes:
redis-data:
EOF
올리기
docker compose up -d --build

상태 확인
docker compose ps



docker compose down
docker compose up -d
→ hits 값이 이어짐
docker compose down -vdocker compose up -d



volumes:
- ./:/app
docker compose down
docker compose up -d --build

→ 동일한 내용 표출되는 것 확인 가능
<h1>DEV MODE: Live Reload via Bind Mount</h1>
http://localhost:9000 새로고침
docker compose restart web실행 후 새로고침