Docker PHP+Apache환경설정: Dockerfile,Docker-compose

도커


1. 도커의 기본 개념

도커(Docker):

도커는 운영체제 위에서 동작하는 프로그램으로, 경량화된 가상 머신(Virtual Machine)으로 생각할 수 있다. 가장 큰 차이는 가상 머신이 운영체제까지 가상화하는 반면 도커는 호스트 운영체제를 그대로 활용한다. 도커는 이미지를 기반으로 컨테이너를 실행하며, 컨테이너는 격리된 환경에서 동작하여 이식성이 뛰어나다.

// VMware같은 가상머신과 비슷한 개념


Dockerfile:

커스텀 이미지를 생성하기 위한 텍스트 파일로, 특정 명령어를 실행하거나 호스트 파일을 복사하는 등의 작업을 정의한다. Dockerfile을 사용하여 도커 이미지를 빌드하고 정의할 수 있다.

// 도커 커스텀 이미지를 생성하기 위한 파일 (커스텀이라는 부분이 중요함)

// 기존 이미지를 이용해 작성순서등을 변경한 커스텀 이미지 파일을 만듬


이미지(Image):

도커에서 프로그램을 빌드, 실행, 배포하기 위한 모든 것을 포함하는 패키지이다. 이미지는 소스 코드, 라이브러리, 런타임 등을 정의하며, Dockerfile을 통해 이미지를 정의하고 빌드할 수 있다. 이미지는 컨테이너에 올라가 실행된다.

// 해당 이미지로 컨테이너를 만든다

// VMware에 들어가는 이미지와 비슷한 개념


컨테이너(Container):

도커 이미지가 실행되는 단위로, 호스트와 격리된 상태에서 동작한다. 도커 이미지와 함께 있으면 어느 환경에서든 실행 가능하며, 가상화된 환경에서 독립적으로 동작한다.


도커 컴포즈(Docker Compose):

여러 컨테이너를 하나의 서비스로 다루기 위한 개념으로, 이미지 하나에 필요한 소프트웨어 및 환경을 정의한다. 도커 컴포즈를 사용하면 여러 컨테이너 간의 관계와 설정을 쉽게 관리할 수 있다. 컴포즈 파일을 통해 서비스를 정의하고 실행할 수 있다.

// 여러 컨테이너를 하나의 서비스로 다루기 위함


DockerFile을 이용해서 커스텀 이미지로 build하는것과, 일반 이미지로 빌드하는것의 차이와 흐름설명 (중요)

  1. Dockerfile 사용해서 커스텀 이미지로 빌드

    Docker-comopse.yml에 기재된 build항목에서 Dockerfile의 로컬 위치를 찾아서 읽음 → Dockerfile에 기재된 이미지 파일을 DockerHub 에서 pull Image → Dockerfile에 기재된 순서와 방법따라서 빌드 → 커스텀 이미지 생성완료→ 이미지로 컨테이너 생성 → 여러 컨테이너를 도커 컴포즈로 제어


    참고파일

    docker-comopse.yml

    services:
      myservice:
        container_name: myapp
        build: dockerfile/path # dockerfile이 있는 경로 지정


    DockerFile

    Dockerfile
    FROM node:18-slim # 도커 허브로 부터 받아올 이미지
    ENV TZ Asia/Tokyo # 커스텀 이미지를 만들며 설정할 옵션


  2. Dockerfile 사용하지 않고 일반 이미지로 빌드

    Docker-comopse.yml에 기재된 image항목을 찾음 → 해당 이미지 파일을 DockerHub 에서 pull Image → 일반 이미지 생성완료→ 이미지로 컨테이너 생성 → 여러 컨테이너를 도커 컴포즈로 제어


    참고파일

    docker-compose.yml

    services:
      myservice:
        image: nginx:1.25.0 # 도커허브로 부터 받아올 이미지



2.명령어 리스트

1. 기본명령

docker image ls // 이미지 조회
docker ps -a // 컨테이너 모두 조회

2. 도커 허브에서 이미지 가져오는 방법 혹은 커스텀 이미지 생성하는 방법

2-1 도커 이미지 pull
docker image pull 레파지토리명[:태그명]

2-2 도커 커스텀 이미지 만들기(빌드)
docker image bulid -t 이미지명[:태그명] Dockerfile경로
// 이미지를 pull해서 새로운 이미지를 생성한다
// -t 명령어는 이미지의 태그명을 추가함
// 태그명을 미지정시 latest로 자동지정

3. 컨테이너 시작

docker start 컨테이너ID

4. 컨테이너 접속

4-1 컨테이너 접속
docker attach 컨테이너ID

4-2 실행되고 있던 컨테이너 접속
docker exec -it 컨테이너ID /bin/bash   // -it 명령어는 터미널 기능활성화후 접속

5. 컨테이너 생성 및 시작

docker run 이미지태그명 // 새로운 컨테이너 생성 후 실행

6. 컨테이너 생성 및 시작 및 접속

docker run -it 이미지태그명 // 이미지 생성된 컨테이너 시작

7. 컨테이너 삭제

docker rm 컨테이너ID

3. DockerFile에 요소에 대해서

FROM

: 빌드할 베이스 이미지를 지정. 이미지가 로컬에 없으면 도커 허브에서 해당 이미지를 검색해 다운. ex) FROM ubuntu:latest

RUN

: 컨테이너에서 실행할 명령어를 지정. 보통 컨테이너에 필요한 라이브러리를 다운받는 명령어나 디렉토리를 만드는 명령어를 지정한다. ex) RUN apt-get update

ADD (COPY명령어와 동일)

: 컨테이너에서 배치할 파일이나 디렉토리를 지정. ex) ADD ./message /message ===> 해당 명령어는 현재 디렉토리에 위치한 message라는 파일을 컨테이너의 루트 디렉토리에 message라는 이름으로 배치하라는 소리다.

CMD

: 컨테이너가 시작할 때 실행할 명령어를 지정. RUN은 이미지를 빌드할 때 실행되고 CMD는 이미 빌드된 이미지(컨테이너)가 시작할 때 실행된다. 여러 CMD는 모두 실행되지 않고 맨 마지막 CMD만 실행된다.

ENTRYPOINT

: CMD와 동일. 하지만 CMD에서는 param값을 대체할 수 있지만 ENTRYPOINT는 불가능하다. ENTRYPOINT와 CMD는 같이 쓰이면서 CMD는 default값을 가진 param을 갖는 명령어를 지정할 때 쓰이고 ENTRYPOINT는 그렇지 않을 때 쓰인다. 또한 CMD와 마찬가지로 여러 ENTRYPOINT는 모두 실행되지 않고 맨 마지막 ENTRYPOINT만 실행된다.

LABEL

: key-value 형식의 메타데이터를 이미지에 추가.

ENV

: LABEL과 동일하지만 메타데이터 대신 환경변수를 설정.

VOLUME

: 컨테이너 내의 특정 디렉토리를 지정. 해당 디렉토리를 외부 경로에 마운트되어 컨테이너가 삭제되어도 해당 디렉토리의 정보는 보존될 수 있게 됨.

외부 경로란 HOST OS의 /var/lib/docker/volumes 경로를 의미한다.


서로 다른 서비스(컨테이너)에서 동일한 디렉토리(데이터)를 공유하는법

version: '3'

services:
  service1:
    image: your-service1-image
    volumes:
      - .:/path/to/shared/directory # 디렉토리가 service2와 동일하다  

  service2:
    image: your-service2-image
    volumes:
      - .:/path/to/shared/directory

WORKDIR

: 이 명령어는 현재 작업 디렉토리를 변경하고, 이후의 명령어들이 해당 디렉토리에서 실행되도록 설정 ( linux의 cd명령어와 동일)

Dockerfile에 아래와 같이 적혀있다면
cd /var/www한 후에 거기서 composer require google/apiclient:~2.0 라는 컴포저 패키지를 설치하라는 말이다

WORKDIR /var/www
RUN composer require google/apiclient:~2.0


DockerFile의 예제

FROM ubuntu:latest // ubuntu:latest 이미지를 로컬에서 먼저 찾아봄. 없으면 docker hub에서 해당 이미지 찾아서 다운

MAINTAINER myname // 관리자설정하며 myname이라는 사람을 관리자로 설정

RUN apt-get install -y // 이미지 빌드시 apt-get install명령어 실행

ADD testfile1 /testfile2 // 현재로컬에 있는 testfile1폴더를 컨테이너의 루트폴터에 testfile2라는 이름으로 복사함

VOLUME /mountcheck 컨테이너에 mountcheck라는 폴더를 생성하고 로컬PC에도 해당 공유폴더를 위치시킴



4. PHP + Apache의 도커 환경설정

1. 아래 파일 생성

[Dockerfile]

FROM php:8.2-apache  
COPY . /var/www/html

[index.php]

<?php  
    phpinfo();  
?>


2.아래 명령어 실행

docker build -t docker-php .   
// 현재 폴더에서 dockerfile을 가지고 커스텀 이미지를 생성한다

docker run -d -p 0.0.0.0:53333:80 docker-php   
//  로컬(호스트PC)의 모든 IP(0.0.0.0)에서 53333포트로 접근시 컨테이너에 80포트로 연결된다
// 1.1.1.1:53333 으로 접근해도 phpinfo()화면이 보임

docker exec -it 컨테이너ID /bin/bash 
// 해당 컨테이너에 접속한다

which php // php설치한곳확인
php --ini // php.ini위치확인
docker-php-ext-install mysqli && docker-php-ext-enable mysqli // 도커기반 php의 extension설치

+ 추가 상세내용은 참조를 확인


5. Docker-compose를 이용한 PHP+Apache+Mysql설정

Dockerfile

FROM php:7.3.3-apache # php7.3이미지를 도커허브로부터 pull
RUN docker-php-ext-install mysqli   # docker용 php extension설치
EXPOSE 80 # 80번포트를 컨테이너로부터 개방


Dockercompose

// 컨테이너끼리 서로 통신한다

version: '3.3'
 
services:
  web: # 컨테이너명1 (php/apache)
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - db
    volumes:
      - ./:/var/www/html/
    ports:
      - 80:80
  db: # 컨테이너명2 (Mysql)
    container_name: mysql8
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_DATABASE: db
      MYSQL_USER: admin
      MYSQL_PASSWORD: admin
      MYSQL_ROOT_PASSWORD: admin
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:4.7
    depends_on:
      - db
    ports:
      - "89:80"
    environment:
      - "PMA_HOST=db"
      - "PMA_USER=admin"
      - "PMA_PASSWORD=admin"

docker-compose로 주로 사용하는 명령어

docker-compose up -d // docker-compose.yml을 참조해서 컨테이너를 생성하고 실행한다 (최초에 이미지가 없으면 빌드해준다)
docker-compose down // docker-compose로 생성된 컨테이너를 정지하고 삭제한다
docker-compose up -d --build  // docker-compose.yml을 참조해서 이미지를 재빌드하고 컨테이너를 생성하고 실행한다 (dockerfile등의 이미지에 수정사항이 있을 경우 사용)


6. Docker-compose를 이용한 Vue3 + flask설정

상세정보는 아래의 깃허브에 있다

실제 사용 repo

version: '3.8' # docker의 버전정보

services:
  backend:
    restart: unless-stopped
    build:
      context: ./backend
      dockerfile: Dockerfile
    command: flask run --port=5000 --debug # 컨테이너가 실행되고 실행될 명령어
    volumes:
      - ./backend:/backend
    ports:
      - "5005:5000"
    environment:
      FLASK_APP: /backend/app.py
      FLASK_RUN_HOST: 0.0.0.0
      FLASK_CONFIG: local

  frontend:
    restart: unless-stopped # 정지없이 실행
    build:
      context: ./frontend
      dockerfile: Dockerfile
    user: "node"
    command: /bin/bash -c "npm install && npm run dev" # 포트개방을 위한 --host 명령은 package.json의 dev명령에 추가함
    depends_on:
      - backend
    volumes:
      - ./frontend:/frontend
    ports:
      - "5555:5173" # 5173포트를 사용하자 6000번 포트사용시 안전하지않다고 경고뜸 


host.docker.internal에 대해서

하나의 컨테이너가 있다

그리고 하나의 컨테이너 내부(호스트머신)에서 웹서버(8080포트)와 mysql(3306)이 서로 통신을 하는 상황이다

로컬PC의 경우는 localhost:8080 , localhost:3306을 통해서 서로 통신할수있다

그러나 호스트머신(도커 컨테이너 내부)은 내부에서는 localhost를 사용할수없다.

그래서 host.docker.internal:8080 , host.docker.internal:3306으로 서로 통신해야한다



참조

Docker환경에서 PHP+Apache환경설정

PHP의 Docker-compose.yml설정

도커 정리

도커+php+nginx (일본어)

docker compose에서 서로 다른 container가 같은 volume을 공유하는 방법

Nov 29, 2023 Views 1125