Posted in: 프로그래밍

Docker-Compose로 PHP + MySQL 묶기

 지금 이 블로그도 그렇듯 서버내 모든 서비스가 도커 내에서 돌아가고 있다. 서버 맨 앞에 nginX를 두고 적절한 도커 컨테이너로 연결을 중계해 준다. 이때 기본 nginX로 다루기 껄끄러운 커넥션은 다시 Rust를 통해 다시 핸들링한다.

파란색 테두리의 서버 안에 있는 nginX가 각 컨테이너로 연결을 중계해준다.

이런 구조속에서 각 컨테이너간 서로 통신해야할 일이 생길수 있다. 나로 같으면 PHP와 MySQL를 서로 연결해줘야 하는 상황이 생긴것이다. 짜피 Docker-Compose를 쓰기에 PHP와 MySQL을 1:1로 연결하는거면 별 문제 없이 할 수 있었겠으나, 1:N (단일 MySQL 컨테이너에 여러개의 의존 컨테이너가 붙는) 구조를 원하고 있었다. 아래에서 external_network를 이용해 서로간 통신하는 구조를 만든것을 설명한다.

하나의 MySQL에 자원을 몰빵해 주고, 각 컨테이너에서 이걸 사용하는 구조다.

여러개와 통신하는 컨테이너

 나로 들자면 MySQL 컨테이너이다. MySQL 컨테이너는 다른 컨테이너에 문제가 생겨도 독립적으로 작동을 이어나간다.

적절한 곳에 mysql 폴더를 만들고 아래와 같이 docker-compose.yml를 작성한다

ersion: "3.8"
services:
  db:
    image: mariadb:latest
    restart: always
    environment:
      MYSQL_DATABASE: "esukmeans"
      MYSQL_USER: "esukmean"
      MYSQL_PASSWORD: "유저 패스워드"
      MYSQL_ROOT_PASSWORD: "루트 페스워드"
    volumes:
      - DB데이터위치:/var/lib/mysql

    networks:
      - backend
      - default

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    links:
      - db

    ports:
      - 127.0.0.1:8081:80

networks:
  backend:
    name: backend

이 때 DB 데이터가 저장될 위치와 DB의 설정을 본인에 맞게 설정한다. ./dbdata 처럼 본인이 적합하게 설정하면 된다. (빈 폴더를 만들어서 거기로 설정하자) phpmyadmin은 내가 작업하기 편하려고 만들었다. 굳이 필요없다면 지워도 된다. phpmyadmin을 지우면 db의 default 네트워크를 지워도 된다. (default는 같은 docker-compose.yml 내에서 사용되는 네트워크이다. docker-compose.yml 내 컨테이너끼리는 default 라는 네트워크를 통하여 서로 통신한다.)

 networks > backend 에 다시 name 옵션이 붙어있는것을 볼 수 있다. name옵션이 안붙으면 mysql_backend 처럼 docker-compose.yml이 있는 폴더명이 prefix로 설정되버린다. 물론 name 옵션을 안쓰고 mysql_backend 처럼 길게길게 쓸 수도 있겠으나, 마찬가지로 편의를 위해 이름을 backend로 지정하였다.

 정상적으로 network가 생성되었다면 docker network ls 로 아래같은 결과를 볼 수 있을것이다:

$ sudo docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f86b16fe4450        backend             bridge              local
b5b60714a7f5        bridge              bridge              local
fef695472c16        host                host                local
1cf52af1a58a        mysql_default       bridge              local
c09ad3a36036        none                null                local

MySQL에 붙는 각각의 컨테이너

 MySQL에 달라 붙는 컨테이너들이다. 예로 들면 PHP, WordPress등이 될 것이다.

version: "3.8"
services:
  php-fpm-74:
    build:
      context: phpfpm-74-build
      dockerfile: ./phpfpm-74

    networks:
      - backend

    volumes:
      - 적절한 mount

    ports:
      - 적절한 포트

networks:
  backend:
    external: true

 여기서 중요한것은 networks에 backend를 정의하고 external 옵션을 부여한 것이다. 위의 MySQL에 사용된 docker-compose에서 name을 abcd로 했으면 backend: 대신에 abcd: 를 입력하면 된다. 이후에 필요한 서비스에서 networks 섹션을 만들어서 끌어오면 된다. 이러면 서로 통신이 가능하다.

version: "3"
services:
  web:
    image: wordpress:php7.4
    ports:
      - ...
    volumes:
      - ...
    restart: always
    external_links:
      - db
    environment:
      WORDPRESS_DB_HOST: db

    networks:
      - backend

networks:
  backend:
    external: true

위 처럼 external_links를 사용할 수도 있다. external_links를 사용하면 networks 내에서 (여기서는 backend) 다른 컨테이너를 찾아낸다.  external_links로 연결되면 해당 서버에서 주소를 컨테이너 IP대신 서비스 명만 입력하면 알아서 찾아주므로 매우 편리해진다. 192.168.0.1:3306 대신에 db:3306 처럼 간편하게 접속할수 있음은 물론, 모종의 사유로 IP가 바뀌었을때도 유연하게 돌아간다.

어쨋든 중요한 키워드는 networks, networks > name, networks > external, external_link 이다. 이를 주제로 찾으면 더 응용한걸 찾을수 있을것 같다.

 docker-compose 버전이 낮으면 안될 수 도 있다. docker-compose 자체의 버전과 docker-compose.yml 상단의 버전이 일정 버전 이하면 알 수 없는 속성이라면서 오류를 뱉어낸다. 이걸 몰라서 골머리를 꽤 앓았었는데, 만약 안되면 꼭 버전을 확인해 보자.

답글 남기기

이메일 주소는 공개되지 않습니다.

댓글을 작성하기 위해 아래의 숫자를 입력해 주세요. *