J-한솔넷

재취업 회사 개발환경 구성 본문

프로그래밍/PHP

재취업 회사 개발환경 구성

jhansol 2024. 12. 15. 17:39

6월 말로 최종 퇴사 처리가 되었지만, 업무는 4월말로 끝이 났었습니다. 약 6개월의 백수(?, 놀기만 한건 아닌데)생활을 끝내고 새로운 회사에 취업을 하게 되었습니다. 회사 분위기도 살펴야하고, 프로젝트 환경, 프로젝트 수행 패턴 등 아직 적응해야할 것이 많아 조금은 긴장된 상태로 지내고 있습니다.

이 중에서 개발환경이 사실 적응이 않되어 제가 사용하던 도커 개발환경을 취업한 회사의 프로젝트에 맞추어 새로 만들었습니다. 본 글은 그 과정에 관련된 내용입니다.

도커 개발환경 구성 조건

  • PHP 7.4, 8.1, 8.2, 8.4 를 선택 가능하도록 한다.
  • 도매인 모드, 사이트 모드 두 가지 모드를 지원해야 한다.
  • 도매인 모드에서는 "프로젝트명"."wd" 또는 "다큐먼트 루트"."프로젝트명"."wd" 형태의 도매인을 지원해야 한다.
  • 사이트 모드에서는 "다큐먼트 루트"."프로젝트명"."wd" 형태가 가능해야 하고, 요청한 주소를 기준으로 다큐먼트 루트로 지정되도록 한다.
  • PHP용 사용자 지정 라이브러를 추가 가능하도록 한다.
  • composer, NodeJs, git, vi 등을 사용할 수 있도록 한다.
  • docker-compose.yml 에서 PHP 버젼, 모드, 커스텀 INI, 다큐먼트 루트 등을 지정할 수 있도록 한다.

Dockerfile 구성

전체 구성은 아래와 같습니다.

FROM ubuntu:latest
ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Seoul
ENV LC_ALL=C.UTF-8

RUN apt update; \
    apt upgrade -y

WORKDIR /DevHome
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime; \
    echo $TZ > /etc/timezone

RUN apt update; \
    apt upgrade -y; \
    apt install -y gnupg curl ca-certificates zip unzip git libpng-dev python3 dnsutils librsvg2-bin fswatch ffmpeg nano apache2; \
    apt install -y software-properties-common; \ 
    apt install -y sudo vim mysql-client; \
    echo tzdata tzdata/Areas select Asia | debconf-set-selections; \
    echo tzdata tzdata/Zones/Asia select Seoul | debconf-set-selections; \
    echo "Asia/Seoul" > /etc/timezone; \
    ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime; \
    add-apt-repository -y ppa:ondrej/php; \
    apt update; \
    apt install -y --fix-missing php7.4-amqp php7.4-apcu php7.4-apcu-bc php7.4-ast php7.4-bcmath php7.4-bz2 php7.4-cli php7.4-curl php7.4-dev php7.4-ds php7.4-enchant \
    php7.4-excimer php7.4-gd php7.4-gearman php7.4-geoip php7.4-gmp php7.4-gnupg php7.4-http php7.4-igbinary php7.4-imap php7.4-ldap php7.4-json php7.4-mailparse \
    php7.4-memcache php7.4-mongodb php7.4-mysql php7.4-opcache php7.4-pgsql php7.4-raphf php7.4-rdkafka php7.4-readline php7.4-soap php7.4-solr php7.4-sqlite3 \
    php7.4-uuid php7.4-xml php7.4-xmlrpc php7.4-xml php7.4-xmlrpc php7.4-yaml php7.4-intl php7.4-mbstring php7.4-zip php7.4-redis php7.4-imagick php7.4-xdebug libapache2-mod-php7.4; \
    apt install -y --fix-missing php8.1-amqp php8.1-apcu php8.1-bcmath php8.1-bz2 php8.1-cli php8.1-curl php8.1-dba php8.1-dev php8.1-ds php8.1-enchant php8.1-gd php8.1-gearman \
    php8.1-gnupg php8.1-gmp php8.1-http php8.1-igbinary php8.1-imagick php8.1-imap php8.1-intl php8.1-ldap php8.1-mailparse php8.1-mbstring php8.1-mcrypt \
    php8.1-mysql php8.1-memcache php8.1-mongodb php8.1-opcache php8.1-pgsql php8.1-readline php8.1-raphf php8.1-rdkafka php8.1-readline php8.1-redis \
    php8.1-soap php8.1-solr php8.1-sqlite3 php8.1-uuid php8.1-xml php8.1-xmlrpc php8.1-xsl php8.1-zip php8.1-xdebug php8.1-yaml libapache2-mod-php8.1; \
    apt install -y --fix-missing php8.2-amqp php8.2-apcu php8.2-bcmath php8.2-bz2 php8.2-cli php8.2-curl php8.2-dba php8.2-dev php8.2-ds php8.2-enchant php8.2-gd php8.2-gearman \
    php8.2-gnupg php8.2-gmp php8.2-http php8.2-igbinary php8.2-imagick php8.2-imap php8.2-intl php8.2-ldap php8.2-mailparse php8.2-mbstring php8.2-mcrypt \
    php8.2-mysql php8.2-memcache php8.2-mongodb php8.2-opcache php8.2-pgsql php8.2-readline php8.2-raphf php8.2-rdkafka php8.2-readline php8.2-redis \
    php8.2-soap php8.2-solr php8.2-sqlite3 php8.2-uuid php8.2-xml php8.2-xmlrpc php8.2-xsl php8.2-zip php8.2-xdebug php8.2-yaml libapache2-mod-php8.2; \
    apt install -y --fix-missing php8.4-amqp php8.4-apcu php8.4-bcmath php8.4-bz2 php8.4-cli php8.4-curl php8.4-dba php8.4-dev php8.4-ds php8.4-enchant php8.4-gd php8.4-gearman \
    php8.4-gmp php8.4-gnupg php8.4-http php8.4-igbinary php8.4-imagick php8.4-imap php8.4-intl php8.4-ldap php8.4-mailparse php8.4-mbstring php8.4-mcrypt php8.4-mcrypt php8.4-memcache \
    php8.4-mongodb php8.4-mysql php8.4-opcache php8.4-pgsql php8.4-raphf php8.4-rdkafka php8.4-readline php8.4-redis php8.4-soap php8.4-sqlite3 php8.4-uuid php8.4-xdebug php8.4-xml \
    php8.4-xmlrpc php8.4-xsl php8.4-yaml php8.4-zip libapache2-mod-php8.4; \
    a2enmod rewrite vhost_alias ssl; \
    curl https://deb.nodesource.com/setup_lts.x | bash -; \
    apt install -y nodejs; \
    php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"; \
    php composer-setup.php --install-dir=/bin --filename=composer; \
    rm -f composer-setup.php

RUN sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 200M/g' /etc/php/7.4/apache2/php.ini; \
    sed -i 's/memory_limit = 128M/memory_limit = 512M/g' /etc/php/7.4/apache2/php.ini; \
    sed -i 's/post_max_size = 8M/post_max_size = 250M/g' /etc/php/7.4/apache2/php.ini; \
    sed -i 's/short_open_tag = Off/short_open_tag = On/g' /etc/php/7.4/apache2/php.ini; \
    echo "xdebug.mode = develop,debug" >> /etc/php/7.4/mods-available/xdebug.ini; \
    echo "xdebug.client_host=host.docker.internal" >> /etc/php/7.4/mods-available/xdebug.ini; \
    echo "xdebug.client_port = 9000" >> /etc/php/7.4/mods-available/xdebug.ini; \
    sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 200M/g' /etc/php/8.1/apache2/php.ini; \
    sed -i 's/memory_limit = 128M/memory_limit = 512M/g' /etc/php/8.1/apache2/php.ini; \
    sed -i 's/post_max_size = 8M/post_max_size = 250M/g' /etc/php/8.1/apache2/php.ini; \
    sed -i 's/short_open_tag = Off/short_open_tag = On/g' /etc/php/8.1/apache2/php.ini; \
    echo "xdebug.mode = develop,debug" >> /etc/php/8.1/mods-available/xdebug.ini; \
    echo "xdebug.client_host=host.docker.internal" >> /etc/php/8.1/mods-available/xdebug.ini; \
    echo "xdebug.client_port = 9000" >> /etc/php/8.1/mods-available/xdebug.ini; \
    sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 200M/g' /etc/php/8.2/apache2/php.ini; \
    sed -i 's/memory_limit = 128M/memory_limit = 512M/g' /etc/php/8.2/apache2/php.ini; \
    sed -i 's/post_max_size = 8M/post_max_size = 250M/g' /etc/php/8.2/apache2/php.ini; \
    sed -i 's/short_open_tag = Off/short_open_tag = On/g' /etc/php/8.2/apache2/php.ini; \
    echo "xdebug.mode = develop,debug" >> /etc/php/8.2/mods-available/xdebug.ini; \
    echo "xdebug.client_host=host.docker.internal" >> /etc/php/8.2/mods-available/xdebug.ini; \
    echo "xdebug.client_port = 9000" >> /etc/php/8.2/mods-available/xdebug.ini; \
    sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 200M/g' /etc/php/8.4/apache2/php.ini; \
    sed -i 's/memory_limit = 128M/memory_limit = 512M/g' /etc/php/8.4/apache2/php.ini; \
    sed -i 's/post_max_size = 8M/post_max_size = 250M/g' /etc/php/8.4/apache2/php.ini; \
    sed -i 's/short_open_tag = Off/short_open_tag = On/g' /etc/php/8.4/apache2/php.ini; \
    echo "xdebug.mode = develop,debug" >> /etc/php/8.4/mods-available/xdebug.ini; \
    echo "xdebug.client_host=host.docker.internal" >> /etc/php/8.4/mods-available/xdebug.ini; \
    echo "xdebug.client_port = 9000" >> /etc/php/8.4/mods-available/xdebug.ini

RUN rm -f /etc/apache2/sites-available/* /etc/apache2/sites-enabled/*; \
    rm -f /etc/apache2/mods-enabled/php*; \
    mkdir -p /usr/lib/php/custom; \
    systemctl stop apache2; \
    systemctl disable apache2


COPY index.php /var/www/html/index.php
COPY svhost.sh /usr/bin/svhost
COPY sphp.sh /usr/bin/sphp
COPY ssl_key/* /etc/ssl/private
ADD phpMyAdmin /var/www/html/myadmin
RUN mkdir -p /var/www/html/myadmin/tmp; \
    chown www-data:www-data /var/www/html/myadmin/tmp; \
    echo "ubuntu ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/ubuntu
COPY docker_entrypoint.sh /usr/bin/docker_entrypoint.sh
COPY confs/* /etc/apache2/sites-available

RUN chmod 0755 /usr/bin/svhost; \
    chmod 0755 /usr/bin/sphp; \
    chmod 0755 /usr/bin/docker_entrypoint.sh

VOLUME [ "/DevHome", '/usr/lib/php/custom' ]

EXPOSE 80 443 5173 8080

ENTRYPOINT [ "docker_entrypoint.sh" ]

CMD ["apache2ctl", "-D", "FOREGROUND"]

도매인모드, 사이트모드를 위한 Apache 설정파일

사이트 모드의 경우 이전에 구성했던 환경과 동일합니다. 그래서 사이트 모드 설정 파일sites.conf 파일은 이전 글을 참고해주세요. 본 글에서는 도매인 모드에 대해서만 추가 설명을 하도록 하겠습니다. 이 설정 파일은 conf 라는 폴더에 함께 작성해두었습니다.

domains.conf

<VirtualHost *:80>
    ServerName localhost
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /var/www/html>
        DirectoryIndex index.php index.html index.htm
        Options Indexes FollowSymLinks Multiviews
        AllowOverride All
        Order allow,deny
        Allow from All
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:80>
    ServerName server.wd
    ServerAlias *.*.wd

    ServerAdmin webmaster@localhost
    VirtualDocumentRoot /DevHome/domains/%2/docroot

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /DevHome/domains/*/docroot>
        DirectoryIndex index.php index.html index.htm
        Options Indexes FollowSymLinks Multiviews
        AllowOverride All
        Order allow,deny
        Allow from All
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:443>
    ServerName server.wd
    ServerAlias *.*.wd

    ServerAdmin webmaster@localhost
    VirtualDocumentRoot /DevHome/domains/%2/docroot

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /DevHome/domains/*/docroot>
        DirectoryIndex index.php index.html index.htm
        Options Indexes FollowSymLinks Multiviews
        AllowOverride All
        Order allow,deny
        Allow from All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateKeyFile /etc/ssl/private/dev.key
    SSLCertificateFile /etc/ssl/private/dev.crt
</VirtualHost>

<VirtualHost *:80>
    ServerName server.wd
    ServerAlias *.wd

    ServerAdmin webmaster@localhost
    VirtualDocumentRoot /DevHome/domains/%1/docroot

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /DevHome/domains/*/docroot>
        DirectoryIndex index.php index.html index.htm
        Options Indexes FollowSymLinks Multiviews
        AllowOverride All
        Order allow,deny
        Allow from All
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:443>
    ServerName server.wd
    ServerAlias *.wd

    ServerAdmin webmaster@localhost
    VirtualDocumentRoot /DevHome/domains/%1/docroot

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /DevHome/domains/*/docroot>
        DirectoryIndex index.php index.html index.htm
        Options Indexes FollowSymLinks Multiviews
        AllowOverride All
        Order allow,deny
        Allow from All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateKeyFile /etc/ssl/private/dev.key
    SSLCertificateFile /etc/ssl/private/dev.crt
</VirtualHost>

위 파일은 총 5개의 virtualHost 블록을 가지고 있습니다.

  • 번째 블록은 http://localhost로 접속했을 때 출력되는 데시보드와 데이터베이스 관리를 위한 PhpMyAdmin 기능을 사용할 수 있습니다.
  • 두 번째 및 세 번째 블록은 "다큐먼트 루트"."프로젝트명"."wd" 형태의 도매인으로 접속하는 경우에 사용됩니다.
  • 네 번째 블록과 다섯 번째 블록은 "프로젝트명"."wd" 형태의 도매인으로 접속하는 경우에 사용됩니다.

첫 번째 블록을 제외한 나머지 블록에는 아래와 같은 VirtualDocumentRoot 라는 항목이 있습니다. 이 부분이 접속하는 도매인 주소에 따라 동적으로 다뮤먼트 루트를 결정하는 핵심적인 부분입니다. 아래 내용 중 %2 는 접속한 도매인 주소를 "."으로 구분했을 때 두 번째 것을 뜻합니다. 이 부분은 주로 "프로젝트명"이 될 것입낟.

VirtualDocumentRoot /DevHome/domains/%2/docroot

위 내용 중 docroot는 다큐먼트 루트 폴더를 지정한 것입니다만. 이 부분은 개발환경 시작 시점에 svhost 명령에 의해 수정될 것입니다. docker-compose.ymlDOCUMENT_ROOT 환경변수 전달받아 svhost가 해당 부분을 대체하도록 되어 있습니다.

sites.conf

이 파일은 전체 내용만 올려두겠습니다.

<VirtualHost *:80>
    ServerName admin.sites.wd
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /var/www/html>
        DirectoryIndex index.php index.html index.htm
        Options Indexes FollowSymLinks Multiviews
        AllowOverride All
        Order allow,deny
        Allow from All
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:80>
    ServerName server.wd
    ServerAlias *.*.wd
    UseCanonicalName Off

    ServerAdmin webmaster@localhost
    VirtualDocumentRoot /DevHome/sites/%2/%1

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /DevHome/sites/*/*>
        DirectoryIndex index.php index.html index.htm
        Options Indexes FollowSymLinks Multiviews
        AllowOverride All
        Order allow,deny
        Allow from All
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:443>
    ServerName server.wd
    ServerAlias *.*.wd
    UseCanonicalName Off

    ServerAdmin webmaster@localhost
    VirtualDocumentRoot /DevHome/sites/%2/%1

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory /DevHome/sites/*/*>
        DirectoryIndex index.php index.html index.htm
        Options Indexes FollowSymLinks Multiviews
        AllowOverride All
        Order allow,deny
        Allow from All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateKeyFile /etc/ssl/private/dev.key
    SSLCertificateFile /etc/ssl/private/dev.crt
</VirtualHost>

HTTPS 프로토콜을 위한 인증서

인증서 파일은 제가 이번에 작업하면서 새로 자체 서명한 인증서 파일을 적용했습니다. 과거의 인증서 파일은 설정 파일에 명기된 ServerName과 일치하지 않아 정상적으로 동작하지 않는 문제가 있었습니다. 이 파을들은 ssl_key 라는 폴더에 넣어 두었습니다.

로컬 호스트 웹 루터 폴드 파일

http://localhost로 접속했을 때 처음에는 현재 가발환경의 사용자가 지정한 모드에서 실행되는 프로젝트 목록과, 시스템 정보를 출력하는 데시보드가 출력되고, 상단에 데이터베이스를 관리하는 PhpMyAdmin 링크가 출력됩니다. /var/www/html 폴더에 index.php, PhpMyAdmin 폴더 가 복사되어 들어갑니다.

index.php

<?php
    function checkSites() {
        if(file_exists('/etc/apache2/sites-enabled/sites.conf')) return 1;
        elseif(file_exists('/etc/apache2/sites-enabled/domains.conf')) return 0;
        else return -1;
    }

    function getDocRoot() {
        $conf = '/etc/apache2/sites-enabled/domains.conf';
        if(file_exists($conf)) {
            $content = file_get_contents($conf, true);
            preg_match_all('/\/DevHome\/domains\/%2\/(.*)/', $content, $matches);
            if(count($matches) == 2) {
                return reset($matches[1]);
            }
        }
        return null;
    }

    $is_sites = checkSites();
    $part_name = null;
    if($is_sites == 1) $part_name = '일반';
    elseif($is_sites == 0) $part_name = '도매인 사이트';
    else $part_name = '미설정';

    $domain_suffix = "wd";
    $sites = array();
    $docroots = array(
        'docroot', 'html', 'public_html', 'public', 'web', 'webroot', 'www', 'wwwroot'
    );

    if($is_sites == 1) {
        $base = '/DevHome/sites';
        $dh = opendir( $base );
        if( $dh ) {
            while( ($entry = readdir( $dh )) ) {
                foreach( $docroots as $docroot ) {
                    if( $entry == '..' || $entry == '.' ) continue;
                    if( filetype( $base . '/' . $entry . '/' . $docroot ) == 'dir' ) {
                        $sites[] = array(
                            'https_url' => "https://$docroot.$entry.$domain_suffix",
                            'http_url' => "http://$docroot.$entry.$domain_suffix",
                            'sitename' => $entry
                        );
                        break;
                    }
                }
            }
        }
    }
    elseif($is_sites == 0 && ($domain_docroot = getDocRoot()) != null) {
        $base = '/DevHome/domains';
        $dh = opendir( $base );
        if($dh) {
            while( ($entry = readdir( $dh )) ) {
                if( $entry == '..' || $entry == '.' ) continue;
                if( filetype( $base . '/' . $entry . '/' . $domain_docroot ) == 'dir' ) {
                    $sites[] = array(
                        'https_url' => "https://www.$entry.$domain_suffix",
                        'http_url' => "http://www.$entry.$domain_suffix",
                        'sitename' => $entry
                    );
                }
            }
        }
    }

?>

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8"/>
        <title>Site Helper</title>
        <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    </head>
    <body>
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <a class="navbar-brand" href="#">Site Helper</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item">
                        <a href="./myadmin" title="phpMyAdmin">데이터베이스 관리</a>
                    </li>
                </ul>
            </div>
        </nav>

        <div class="container mt-5">
            <div class="card">
                <div class="card-header">사이트 목록 (<?=$part_name?>)</div>
                <div class="card-body">
                    <?php foreach( $sites as $site ): ?>
                        <div class="d-inline-block rounded m-2 bg-white" style="box-shadow: 1px 1px 10px 1px #aaa">
                            <div class="d-inline-block px-4 py-2 bg-info text-white"><?=$site['sitename']?></div>
                            <div class="d-inline-block p-2">
                                <a class="m-1 p-1 text-success" href="<?=$site['https_url']?>" title="https">https</a>
                                <a class="m-1 p-1 text-secondary" href="<?=$site['http_url']?>" title="http">http</a>
                            </div>
                        </div>
                    <?php endforeach; ?>
                </div>
            </div>
        </div>

        <div class="container mt-5">
            <div class="card">
                <div class="card-header">시스템 정보</div>
                <div class="card-body">
                    <?php phpinfo(); ?>
                </div>
            </div>
        </div>
    </body>
</html>

PhpMyAdmin 의 config.inc.php

본 개발환경은 도커를 기반으로 실행됩니다. 그래서 config.inc.phpconfig.sample.inc.php를 복사한 후 접속 서버 정보를 아래와 같이 호스트 정보를 host.docker.internal로 수정해주어야 합니다.

<?php
/**
 * phpMyAdmin sample configuration, you can use it as base for
 * manual configuration. For easier setup you can use setup/
 *
 * All directives are explained in documentation in the doc/ folder
 * or at <https://docs.phpmyadmin.net/>.
 */

declare(strict_types=1);

/**
 * This is needed for cookie based authentication to encrypt the cookie.
 * Needs to be a 32-bytes long string of random bytes. See FAQ 2.10.
 */
$cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */

/**
 * Servers configuration
 */
$i = 0;

/**
 * First server
 */
$i++;
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
/* Server parameters */
$cfg['Servers'][$i]['host'] = 'host.docker.internal';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = false;

/** 이하 생략 */

사용자 지정 PHP 라이브러리 추가를 위한 설정

새로 취업한 회사에서는 본인 인증을 위해 국내 서비스 기업의 PHP 전용 라이브러리를 사용하고 있었습니다. 이렇게 환경에 따라 라이브러리가 추가되어야 할 경우를 대비하여 docker-compose.yml 이 있는 폴더 아래에 lib라는 폴더를 생성하고, 폴더에 적용할 라이브러리 파일과 라이브러리를 로드하기 위한 INI 파일을 넣어 둡니다. 설정파일의 예는 아래와 같습니다.

custom-sample.ini

extension=/usr/lib/php/custom/okcert3_2.0.2_ext_linux64_glibc2.17__8.1.so

docker-compose.yml

도커 컴포즈를 이용하여 개발환경을 실행하기 위한 파일로 위 내용을 모두 적용하도록 한 파일을 예로 올려 둡니다. 이 파일을 직접 수정해서 사용하거나 뒤에 소개될 dinit.sh를 이용하여 간단하게 만들어 줄 수도 있습니다.

name: PHP_DEV

volumes:
  sql_data:

services:
  db:
    image: mariadb
    command: --max_allowed_packet=536870912
    environment:
      MARIADB_ROOT_PASSWORD: mysql
    ports:
      - 3306:3306
    volumes:
      - sql_data:/var/lib/mysql

  web:
    image: pig482/devenv:ap78
    environment:
      PHP: 8.1
      CONF: domains
      CUSTOM_INI: custom.ini
      DOCUMENT_ROOT: public
    ports:
      - 80:80
      - 443:443
      - 5173:5173
      - 8080:8080
    volumes:
      - ./webroot:/DevHome
      - ./lib:/usr/lib/php/custom

docker_entrypoint.sh

도커 개발환경이 실행될 때, 이 파일은 docker-compose.yml에 기록된 환경변수를 받아 실행하도록 합니다. 저의 경우 이 파일에는 PHP, CONF, CUSTOM_INI, DOCUMENT_ROOT 등의 환경변수를 받아 Apache 웹서버가 동작하도록 합니다.

#!/bin/bash

/usr/bin/sphp "$PHP"
/usr/bin/svhost "$CONF" "$DOCUMENT_ROOT"
if [ -f "/usr/lib/php/custom/${CUSTOM_INI}" ]; then
    ln -s "/usr/lib/php/custom/${CUSTOM_INI}" "/etc/php/${PHP}/apache2/conf.d/35-${CUSTOM_INI}"
    ln -S "/usr/lib/php/custom/${CUSTOM_INI}" "/etc/php/${PHP}/apache2/conf.d/35-${CUSTOM_INI}"
    ln -s "/usr/lib/php/custom/${CUSTOM_INI}" "/etc/php/${PHP}/cli/conf.d/35-${CUSTOM_INI}"
    ln -S "/usr/lib/php/custom/${CUSTOM_INI}" "/etc/php/${PHP}/cli/conf.d/35-${CUSTOM_INI}"
fi
exec "$@"

sphp.sh

이 스크립트 파일은 개발환경 내에서 PHP 버전을 변경하는 기능을 가지고 있습니다. 내용은 아래와 같습니다.

#!/bin/bash

if [ "$1" == "7.4" ]; then
    a2enmod php7.4
    update-alternatives --set php /usr/bin/php7.4
elif [ "$1" == "8.1" ]; then
    a2enmod php8.1
    update-alternatives --set php /usr/bin/php8.1
elif [ "$1" == "8.2" ]; then
    a2enmod php8.2
    update-alternatives --set php /usr/bin/php8.2
elif [ "$1" == "8.4" ]; then
    a2enmod php8.4
    update-alternatives --set php /usr/bin/php8.4
fi

svhost.sh

이 스크립트 파일은 Apache 웹 서버가 도매인모드, 사이트 모드 중 하나로 동작하도록 합니다. 내용은 아래와 같습니다.

#!/bin/bash

# 도메인 기반 사이트 환경설정 활성화
function domain_link()
{
    file="/etc/apache2/sites-available/domains.conf"
    if [ -e $file ]; then
        sed -i "s/\/DevHome\/domains\/%2\/.*$/\/DevHome\/domains\/%2\/$1/g" $file
        sed -i "s/\/DevHome\/domains\/%1\/.*$/\/DevHome\/domains\/%1\/$1/g" $file
        sed -i "s/\/DevHome\/domains\/\*\/[^>]*/\/DevHome\/domains\/\*\/$1/g" $file
        if [ ! -e "/etc/apache2/sites-enabled/domains.conf" ]; then
            ln -s $file "/etc/apache2/sites-enabled/domains.conf"
        fi
        echo 1
    else
        echo 0;
    fi
}

# 개별 사이트 환경설정 활성화
function sites_link()
{
    file="/etc/apache2/sites-available/sites.conf"
    if [ -e $file ]; then
        if [ ! -e "/etc/apache2/sites-enabled/sites.conf" ]; then
            ln -s $file "/etc/apache2/sites-enabled/sites.conf"
        fi
        echo 1
    else
        echo 0
    fi
}

case $1 in
    sites)
        sites_link
        ;;
    domains)
         domain_link $2
        ;;
esac

dinit.sh

이 파일은 없어도 되는 파일입니다. docker-compose.yml을 직접 편집하기 힘든 사용자를 위한 스크립트 파일입니다. 내용은 아래와 같습니다.

#!/bin/bash

PHP=""
CONF=""
CUSTOM_INI=""
DOCUMENT_ROOT=""

EXIT=0
while [ $EXIT -eq 0 ]
do
    echo " 1. Init Directory (webroot, webroot/sites, webroot/domains, lib) "
    echo ""
    echo " Domains Evironment "
    echo " 2. PHP 7.4 "
    echo " 3. PHP 8.1 "
    echo " 4. PHP 8.2 "
    echo " 5. PHP 8.4 "
    echo ""
    echo " Sites Environment "
    echo " 6. PHP 7.4 "
    echo " 7. PHP 8.1 "
    echo " 8. PHP 8.2 "
    echo " 9. PHP 8.4 "
    echo " 0. Exit "

    read -p "Select Number : " NO
    case "$NO" in
        1)
            mkdir webroot 2> /dev/null
            mkdir -p webroot/sites 2> /dev/null
            mkdir -p webroot/domains 2> /dev/null
            mkdir -p lib 2> /dev/null
            ;;
        2)
            PHP="7.4"
            CONF="domains"
            EXIT=1
            ;;
        3)
            PHP="8.1"
            CONF="domains"
            EXIT=1
            ;;
        4)
            PHP="8.2"
            CONF="domains"
            EXIT=1
            ;;
        5)
            PHP="8.4"
            CONF="domains"
            EXIT=1
            ;;
        6)
            PHP="7.4"
            CONF="sites"
            EXIT=1
            ;;
        7)
            PHP="8.1"
            CONF="sites"
            EXIT=1
            ;;
        8)
            PHP="8.2"
            CONF="sites"
            EXIT=1
            ;;
        9)
            PHP="8.4"
            CONF="sites"
            EXIT=1
            ;;
        0)
            exit 0
            ;;
        *)
            echo " Wrong number."
            ;;
    esac
done

if [ $EXIT -eq 1 ]; then
    read -p "PHP Custom extension ini file name : " INI
    if [ -f "./lib/${INI}" ]; then
        CUSTOM_INI=$INI
    fi

    read -p "Type Document root directory name (Domains only) : " DIR
    DOCUMENT_ROOT=$DIR

    if [ -f "docker-compose.yml" ]; then
        rm -f docker-compose.yml
    fi

    echo "name: PHP_DEV" > docker-compose.yml
    echo "" >> docker-compose.yml
    echo "volumes:" >> docker-compose.yml
    echo "  sql_data:" >> docker-compose.yml
    echo "" >> docker-compose.yml
    echo "services:" >> docker-compose.yml
    echo "  db:" >> docker-compose.yml
    echo "    image: mariadb" >> docker-compose.yml
    echo "    command: --max_allowed_packet=536870912" >> docker-compose.yml
    echo "    environment:" >> docker-compose.yml
    echo "      MARIADB_ROOT_PASSWORD: mysql" >> docker-compose.yml
    echo "    ports:" >> docker-compose.yml
    echo "      - 3306:3306" >> docker-compose.yml
    echo "    volumes:" >> docker-compose.yml
    echo "      - sql_data:/var/lib/mysql" >> docker-compose.yml
    echo "" >> docker-compose.yml
    echo "  web:" >> docker-compose.yml
    echo "    image: pig482/devenv:ap78" >> docker-compose.yml
    echo "    environment:" >> docker-compose.yml
    echo "      PHP: ${PHP}" >> docker-compose.yml
    echo "      CONF: ${CONF}" >> docker-compose.yml

    if [ -n "./lib/${CUSTOM_INI}" ]; then
        echo "      CUSTOM_INI: ${CUSTOM_INI}" >> docker-compose.yml
    fi

    echo "      DOCUMENT_ROOT: ${DOCUMENT_ROOT}" >> docker-compose.yml
    echo "    ports:" >> docker-compose.yml
    echo "      - 80:80" >> docker-compose.yml
    echo "      - 443:443" >> docker-compose.yml
    echo "      - 5173:5173" >> docker-compose.yml
    echo "      - 8080:8080" >> docker-compose.yml
    echo "    volumes:" >> docker-compose.yml
    echo "      - ./webroot:/DevHome" >> docker-compose.yml

    if [ -n "./lib/${CUSTOM_INI}" ]; then
        echo "      - ./lib:/usr/lib/php/custom" >> docker-compose.yml
    fi

    echo "Init docker-compose.yml file"
fi

파일 준비

위 내용의 모든 파일은 저의 Github 저장소에 등록되어 있습니다. 저장소의 내용을 내려 받아 활용하는 것이 편할 것입니다. 폴더 구조를 간단하게나마 보자면 아래와 같습니다.

.
├─confs
│ ├─domains.conf
│ └─sites.conf
├─phpMyAdmin
│ └─config.inc.php
├─custom-sample.ini
├─dinit.sh
├─Dockerfile
├─index.php
├─sphp.sh
├─svhost.sh
└─ssl_key
  ├─dev.crt
  └─dev.key

도커 이미지 빌드

저의 경우 Docker Hub에 제가 작성한 이미지를 등록해두고 화룡하고 있습니다. 아래와 같이 빌드를 하지 않고 제가 올려둔 이미지를 이용할 수도 있습니다. 저는 아래와 같이 빌드하여 도커 호브에 푸시했습니다.

j-hansol / Dev-Environment

docker build -t pig482/devenv:ap78 .
docker push pig482/devenv:ap78

docker-compose 파일 생성

위에 언급한 docker-compose.yml을 아래와 같이 dinit.sh를 이용하여 생성합니다. 참고로 저는 wsl 환경에서 실행했습니다. 아래와 같이 모드와 PHP 버전을 번호를 입력하여 선택하고 라이브러리 설장 파일의 이름을 지정하고, 마지막으로 다큐먼트 루트 폴더명을 입력하면 docker-compose.yml 이 완성됩니다.

$ sh dinit.sh
 1. Init Directory (webroot, webroot/sites, webroot/domains, lib)

 Domains Evironment
 2. PHP 7.4
 3. PHP 8.1
 4. PHP 8.2
 5. PHP 8.4

 Sites Environment
 6. PHP 7.4
 7. PHP 8.1
 8. PHP 8.2
 9. PHP 8.4
 0. Exit
Select Number : 3
PHP Custom extension ini file name : custom.ini
Type Document root directory name (Domains only) : public
Init docker-compose.yml file
$

개발환경 실행

개발관경 실행과 종료는 아래의 명령을 이용하면 됩니다.

개발환경 실행

docker-compose up -d

개발환경 종료

docker-compose down

개발환경 접속

docker-compose exec web bash

또는

docker-compose exec -u ubuntu web bash

웹 브로우즈 접속

데시보드와 데이터베이스 관리를 위해서는 아래와 같이 접속합니다.

http://localhost

각 프로젝트 사이트 접속은 아래와 같이 가능합니다. 예를 들자면...

http://public.project.wd
https://public.project.wd
http://project.wd
https://project.wd

마치며

자세하게 기록하자면 너무 많아 간단하게 적는다고 적었는데 그래도 내용이 많은 듯 하네요. 나름데로 회사에서 진행하는 프로젝트나, 저의 개인적으로 진행하는 사이드 프로젝트 등에 잘 활용할 듯 합니다. 무엇보다 본인 인증과 같은 기능을 추가하는 경우 위부 라이브러리를 사용할 수 있도록 만들었다는 점에서 매우 흡족합니다.

그리고 회사에서는 XAMPP를 이용하고 있는데, 이 환경에서는 외부 라이브러리를 적용할 수 없다는 점에서 "역시 개발은 linux, Mac, Docker 환경이 좋구나" 하는 생각을 했습니다.

'프로그래밍 > PHP' 카테고리의 다른 글

Nginx 기반 Docker 개발환경 만들기, 삽질기  (0) 2024.06.18
Laravel 용 패키지 만들기, 삽질기  (0) 2024.06.02
삽질의 연속  (0) 2024.04.20
메모리 프로파일링?  (0) 2023.11.09
ChatGPT를 이용한 코딩?  (0) 2023.10.26