현대 오토에버 클라우드 스쿨

도커 네트워크와 docker-compose를 이용한 2개의 컨테이너 연동

Gom3rye 2025. 6. 24. 16:33
728x90
  • Docker: 컨테이너 기반의 가상화 도구
    • Image
    • Container
    • Volume
    • Network
  • 이미지를 만드는 방법
  1. 현재 컨테이너를 commit 이라는 이미지로 만들기
  2. Dockerfile에 적어서 만들기
  • 이미지를 올려놓는 방법
  1. Docker Hub (퍼블릭하게 저장)
  2. Private Image Registry (로컬에서 이미지 저장소를 직접 운영)
  • Network, docker-compose, docker-swarm, kubernetes ⇒ 컨테이너 2개 이상: 컨테이너 오케스트레이션

python application, redis db 한 컴퓨터에 설치 → 하나가 고장나면 다른 하나도 멈춤 → 무중단 x

python application과 redis db를 각각 다른 컴퓨터에 설치해서 사용하기 시작 → 자원의 낭비와 확장과 축소 힘듦

한 컴퓨터에 가상환경을 여러 개 두고 각 가상환경에 python application과 redis db를 설치 → 자원의 낭비 문제 해결 but 로드밸런싱 힘듦 문제

구조 장점 단점 적합 상황

한 서버에 모든 구성요소 설치 단순, 저비용 장애 시 전체 다운 개인 실습, 소규모
서로 다른 컴퓨터에 배포 장애 격리, 확장성 일부 확보 자원 낭비, 운영 복잡 중규모 서비스
하나의 서버에 여러 가상환경 구성 자원 효율, 관리 유연성 확장성/고가용성 한계 테스트, CI 환경
클러스터/Kubernetes 사용 확장성, 무중단, 자동 복구 복잡한 설정, 초기 러닝 커브 운영 서비스, 대규모
  • docker-compose는 로드밸런싱까지는 못 함, 수동으로 해줘야 한다.
  • Conatainer는 Local Machine에 종속되지만 다른 Container와 격리되어 있다. (다른 컴퓨터처럼 취급된다.)
    • 네트워크가 왜 필요한지
  • 어제 실습 환경 review

docker engine에다 redis(IP)를 만들었고 로컬에 python application(포트)을 만들었다.

docker engine은 기본적으로 다 막혀있어서 python app이 redis에 접근하기 위해서는 docker engine이 열어줘야 한다. by 포트포워딩 → redis의 ip:port(6379), 컴퓨터의 ip:port(6379) (어차피 도커 엔진과 컨테이너는 컴퓨터의 ip 아니까 포트만 적어줘도 된다.)

Redis IP:6379 ↔ localhost:6379 로 소통했었다.

근데 python application은 로컬에 있으니까 항상 그 위치에 가서 python app.py를 돌려야 한다. ⇒ 번거롭다. → Dockerfile로 이미지 만들어서 컨테이너로 실행

But 컨테이너도 자신이 컴퓨터라고 생각한다. 따라서 python application에서 localhost라고 쓰면 자기 컨테이너로 들어간다. redis로 들어가는 게 아니라.

⇒ 해결 방법: 어차피 내부에 있으니까 내부 네트워크로 연결해주자 (네트워크를 만들어준다 = 너랑 나랑은 같은 곳이야. (밖에서 subneting으로 해주던 것과 똑같다.))

컨테이너끼리 통신

Python의 플라스크로 웹 페이지를 출력하고 redis의 인메모리 데이터베이스에서 웹 페이지 액세스 카운트를 캐시해서 페이지에 출력하려고 한다.

  • 레디스 컨테이너 생성 방법
docker run --name myredis -d -p 6379:6379 redis
# 확인
docker ps
  • 파이썬 flask 애플리케이션 생성(가상 환경을 만들어서 수행: 모든 패키지가 requirements에 기록되는 것을 방지) (현재 위치: kyla@master:~/docker/web$)
python3 -m venv ./myvenv
# 활성화
source myvenv/bin/activate
  • 필요한 패키지 설치
pip install flask
pip install redis
  • 파이썬 패키지 의존성을 파일로 전송
pip freeze > requirements.txt
  • 플라스크를 이용한 웹 페이지 생성 - vi app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
def web_hit_cnt():
    with redis.StrictRedis(host='localhost', port=6379) as conn:
        return conn.incr("hits")

@app.route("/")
def hello():
    cnt = web_hit_cnt()
    return "<p>Web Access Count: {} times</p>".format(cnt)
    
if __name__ == "__main__":
		# 0.0.0.0 : 모든 대역의 사람들이 들어올 수 있게
    app.run(host="0.0.0.0", port=9000, debug=True) 
  • 실행
python app.py
# 포트포워딩 했는데도 안되면 ufw allow 9000 해주기
  • python 애플리케이션을 이미지로 만들 수 있는 Dockerfile 생성 - vi Dockerfile
FROM python:3.10-slim
ENV LIBRARY_PATH=/lib:/usr/lib # 환경 변수 만드는 거라 이 3개 없어도 됨
ENV FLASK_APP=py_app
ENV FLASK_ENV=development

EXPOSE 9000 # 9000번 포트를 외부로 노출할 거야
WORKDIR /py_app
COPY . . # 현재 디렉토리에 있는 모든 자료를 workdir로 복사한다. (python은 이렇게 해줘야 한다.)
RUN pip install -r requirements.txt

# 실행하는 명령
ENTRYPOINT ["python"] # 주 명령어
CMD ["app.py"] # 매개변수
  • 이미지 빌드
docker build -t flaskapp .
  • 컨테이너 실행
docker run -dit -p 9000:9000 --name=flaskapp flaskapp

→ 컨테이너 실행 후 웹 브라우저에서 접속을 하면 에러가 발생

이유: 플라스크 애플리케이션이 컴퓨터에 직접 설치된 경우는 redis가 포트포워딩이 되어 있다면 localhost로 접속이 가능하지만 플라스크 애플리케이션이 도커 컨테이너가 되면 localhost는 컨테이너에 부여된 IP가 되므로 redis에 접속할 수 없어서 에러가 된다.

해결방법:

  • app.py의 접속 IP를 수정해서 이미지를 다시 만들고 컨테이너로 배포
  • 기존 플라스크 컨테이너는 중지하고 이미지와 함께 삭제 (redis 컨테이너는 중지하고 삭제할 필요 없음)
docker stop flaskapp
docker rm flaskapp
docker rmi flaskapp
  • redis 접속 IP를 확인 (컨테이너의 IP 확인 가능)
docker inspect network bridge  # "IPv4Address": "172.17.0.2/16"
  • app.py 의 소스 코드에서 redis 접속 위치를 수정 (localhost에서 172.17.0.2로)

  • 이미지를 다시 생성
docker build -t flaskapp .
  • 컨테이너를 생성해서 접속
docker run -dit -p 9000:9000 --name=flaskapp flaskapp
  • 확인
docker ps

→ 이번엔 제대로 나오는 것을 확인할 수 있다.

  • 정리
docker stop flaskapp
docker rm flaskapp
docker rmi flaskapp
docker stop myredis
docker rm myredis
docker rmi redis

✅ 핵심 요약

상황 접근 방식 이유

로컬 Python → Docker Redis localhost:6379 Redis 포트를 호스트에 포워딩함
Docker Python → Docker Redis (다른 컨테이너) ❌ localhost (오류 발생)✅ myredis 컨테이너끼리는 localhost가 아님→ Docker 내부 네트워크에서 컨테이너 이름으로 접근
컨테이너끼리 소통 Docker 네트워크 공유 + 컨테이너 이름 사용 DNS처럼 작동하는 브리지 네트워크 기능 활용

도커 네트워크와 docker-compose를 이용한 2개의 컨테이너 연동

위의 작업을 docker-compose로 해보기

  • 현재 디렉토리에 docker-compose.yml 파일 만들기
    version: '3'
    services:
      redis: # 컨테이너 이름
        image: redis:latest
        ports:
          - 6379:6379
        restart: always
    
      flask:
        build: . # 현재 디렉토리에 있는 Dockerfile을 기반으로 이미지 빌드를 하겠다
        ports:
          - 9000:9000
        restart: always
        depends_on:
          - redis
    → 각각을 쓰레드로 만들기 때문에 순서가 보장되지 않음 ⇒ 의존성으로 순서를 써줘서 flask는 Redis 컨테이너가 "시작 명령"을 받은 후에 실행되도록 해야 한다.
  • app.py에서 ip를 적는게 아니라 컨테이너 이름을 적어주기

→ redis 접속 코드를 서비스 이름으로 접속하도록 수정

  • docker-compose 실행
docker-compose up -d
  • 컨테이너 잘 띄워졌는지 확인
docker ps

→ redis가 먼저 띄워진거 확인할 수 있다.

명령어

  • build: Dockerfile을 이용한 빌드 또는 재빌드
  • config: 내용 확인
  • create: 서비스를 생성
  • up: 컨테이너 서비스 생성하고 시작
  • down: 서비스 중지
  • events: 이벤트 정보 수신
  • exec: 실행 중인 컨테이너에 명령을 실행
  • logs: 로그 정보 출력
  • restart: 서비스 재시작
  • rm: 서비스 제거
  • scale: 컨테이너 서비스에 대한 컨테이너 수 설정
  • start: 서비스 시작
  • stop: 서비스 중지

옵션

  • d
  • --build: 컨테이너를 실행하기 전에 이미지를 빌드
  • --force-recreate: 변경된 내용이 없어도 컨테이너를 재생성
  • --scale SERVICE=NUM: 컨테이너의 수를 변경
  • --abort-on-container-exit: 컨테이너가 하나라도 종료되면 모든 컨테이너를 종료
  • --remove-orphans: 컴포즈 파일에 정의되지 않은 서비스의 컨테이너를 종료

컨테이너 생성 (깨끗하기 위해 compose 디렉토리를 만들고 그 안에서 작업)

  • vi docker-compose.yml
version: '3.8'

services:
  server_web: # 컨테이너이름
    image: httpd:2 # 아파치 웹 서버 가져오고 싶으면
  server_db:
	  image: redis:latest
  • 컨테이너 실행
docker-compose up -d
  • 컨테이너 확인
docker ps

  • 컨테이너 중지
docker-compose down

scale up

docker-compose up --scale server_db=3 --scale server_web=3 -d

→ 이미지는 있으니까 금방 만든다.

⇒ 일반 컨테이너로 생성했다고 하면 중지시키려면 명령어 6번 써야 한다. But, 지금은 docker-compose down 만 하면 된다.

docker-compose [-f 파일경로] down [옵션]

docker-compose 삭제

  • rmi 종류: 이미지도 같이 삭제하는 것으로 all을 설정하면 모든 이미지가 삭제되고 local로 지정하면 커스텀 태그가 없는 이미지만 삭제
  • -v: 기재된 볼륨 삭제
  • --remove-orphans: 컴포즈 파일에 정의되지 않은 서비스의 컨테이너도 삭제

docker-compose logs -f

로그 확인

docker-compose config

yaml 파일 확인

  • volume은 안 만들어 주는데 network는 만들어준다.

728x90
반응형