APM - Apache 와 PHP-FPM 설치 연동

Last Updated on 1월 4, 2021 by 태랑(정현호)


* 변경 추가 내용이 있다면 추가적으로 개선 업데이트 중입니다


먼저 Source Compile 로 APM 스택 구성  - 3번째 PHP 설치  글로 연관된 이전글 아래와 같습니다

1. Apache 2.4 + OpenSSL 1.1.1 Source Compile 설치
2. Mysql 5.7 설치 - Source Compile / Binary 설치


APM 연동은 Apache -> Mysql -> PHP 순으로 진행 됩니다.


[참고1] CentOS 7.8 버전에 YUM(RPM) 으로 APM 설치는 아래 포스팅을 참조하시면 됩니다.


[참고2] CentOS 8.3 버전에 DNF(RPM) 으로 APM 설치는 아래 포스팅을 참조하시면 됩니다.








PHP-FPM 으로 전환



Oracle Cloud 프리티어로 이전하면서 초기의 구성은 Apache + mod_php + Tomcat  으로 사용하였습니다.


이런 구성에서 블로그와 페도라 한국 사용자 모임의 사이트 변경을 위해 신규 개발 소스를 배포 하다보니 Apache의 부하나 메모리 사용량이 증가 하였고 1번 서버의 메모리도 부족해 지는 상황이 되었습니다.

그래서 구조를 변경 하기로 결정하였으며 1개의 서버에서 Apache + Mod_PHP 로 운영하는 구조를 2개의 서버로 분리하여 Apache + PHP-FPM 로 구성하는 것으로 변경 하게 되었습니다.


Free Tier 계정을 추가로 발급 받아 Instance를 2대를 더 확보 하여 서버를 분리 하였고
Cloud Tenancy 간의 Local-Peer 연결은 오라클 김범준 엔지니어의 도움을 받았습니다.






CGI 와 Fast CGI



CGI는 요청(Request)가 들어올때 때마다 신규 프로세스를 생성/구동하여 이 과정에서 부하 증가 등의 이슈가 있으며 ​FastCGI의 경우 FastCGI 어플리케이션 구동 시  미리 프로세스를 생성한 뒤 해당 프로세스를 활용함으로써 일반 속도가 빠르고 부하가 적습니다

또한 apache 에 모듈로 함께 수행되는 mod_php 방식에 비해 프로세스와 데몬이 별도로 분리 되어 있는 방식의 php-fpm 이 apache의 부하나 사용량을 줄일수 있습니다.

성능에 대한 비교는 아래 내용을 참고해보시면 됩니다.







Apache 설치 정보



Apache 는 2.4.46 버전 과 OpenSSL 1.1.1 버전을 Compile 하여 설치 하였으며 MPM은 event 방식으로 설치 하였습니다.

자세한 설치내역은 아래 이전글을 참조하시면 됩니다.




사용한 configure 내역

[root]# export CPPFLAGS="-I/usr/local/openssl-1.1.1h"

[root]# ./configure --prefix=/usr/local/apache2.4.46 \
--enable-mods-shared=all --enable-http2 \
--enable-ext-filter --enable-ssl \
--with-ssl=/usr/local/openssl-1.1.1h \

--enable-so --enable-cache --enable-proxy \
--enable-deflate --enable-suexec --enable-file-cache \
--with-mpm=event --with-apr=/usr/local/apr-1.7.0 \
--with-apr-util=/usr/local/apr-util-1.6.1 \
--with-pcre=/usr/local/pcre-8.44/bin/pcre-config \
--enable-modules=all --enable-module=shared






PHP 설치 및 구성



먼저 Apache 의 mpm 방식을 thread 방식인 worker나 event 방식으로 설치 하였을 경우 mysql 도 관련 된 옵션(--enable-thread-safe-client)으로 설치가 되어야 그렇지 못할 경우 libmysqlclient_r 라이브러리를 참조 할수 없어서 에러가 발생 합니다

하지만 cmake 로 설치 되는 버전부터는 --enable-thread-safe-client  옵션을 줄수가 없어서 심볼릭 링크로 대체 해야 합니다.




Mysql Library 심볼릭 링크 생성


[root]# cd /usr/local/mysql/lib
--> 설치된 디렉토리에서  lib 디렉토리로 이동합니다.


아래 구문을 그대로 실행하여 심볼릭 링크를 생성 하면 됩니다
[root]# for f in libmysqlclient.so*; do ln -s $f $(echo $f | sed s/libmysqlclient/libmysqlclient_r/); done

[root]# ln -s libmysqlclient.a libmysqlclient_r.a






[참고] 현재 글은 PHP 7.2 설치의 내용 입니다. 
PHP 7.4 설치에 관한 내용이 필요하시면 아래 링크를 참조하시면 됩니다
지금 기준으로 PHP 7.4를 설치 하는 과정에서 몇가지 에러와 필요한 패키지를 소스 컴파일해서 설치를 해야 하기 때문에 설치 하실 버전은 설치 과정 등을 고려 해서 선택 하시면 될것 같습니다.





다운로드 및 설치

[root]# wget https://www.php.net/distributions/php-7.2.33.tar.gz

[root]# tar zxvf php-7.2.33.tar.gz
[root]# cd php-7.2.33


[root]# ./configure --prefix=/usr/local/php-7.2.33 \
--with-apxs2=/usr/local/apache2.4.43/bin/apxs \

--with-config-file-path=/etc \
--with-pdo-mysql=/usr/local/mysql --enable-soap \
--enable-mbstring --with-gd=shared --with-gd \
--with-jpeg-dir
 --enable-sockets --with-openssl \
--with-zlib --with-gettext --enable-sigchild \
--with-iconv --with-libxml-dir --with-png-dir \

--enable-opcache --enable-fpm \
--with-fpm-user=apache --with-fpm-group=apache \

--with-freetype-dir --with-curl --enable-exif \
--enable-zip --enable-bcmath
 --enable-mbstring=all \
--with-mysqli=/usr/local/mysql/bin/mysql_config


[root]# make; make install






설치 후 심볼릭 링크 생성

[root]# cd /usr/local
[root]# ln -s  php-7.2.33  php
-> 심볼릭 링크 생성은 필수는 아닙니다 경로의 단일화를 위해 하는 것이나 이 작업은 필수는 아닙니다.




.bash_profile 에 path 추가

[root]# vi .bash_profile

export PATH=$PAHT:/usr/local/php-7.2.33/bin:/usr/local/php-7.2.33/sbin







추가 모듈 설치



mcrypt 모듈 설치

wget https://pecl.php.net/get/mcrypt-1.0.3.tgz
tar xvzf mcrypt-1.0.3.tgz
cd mcrypt-1.0.3
phpize
./configure --with-php-config=/usr/local/php-7.2.33/bin/php-config
make -j 3 && make install





imagick 모듈 설치

yum -y install ImageMagick-devel

wget http://pecl.php.net/get/imagick-3.4.4.tgz

tar zxvf imagick-3.4.4.tgz
cd imagick-3.4.4

/usr/local/php-7.2.33/bin/phpize

./configure --with-php-config=/usr/local/php-7.2.33/bin/php-config
make && make install






php.ini 파일 수정



먼저 php.ini 파일이 /etc 위치에 없을 경우 설치 source 파일 디렉토리에서 복사를 합니다.

[root]# cd /설치소스경로

[root]# cp php.ini-production /etc/php.ini




php.ini 파일 수정


[root]# vi /etc/php.ini

아래 6개는 주석 제거 및 내용 수정

extension_dir = "/usr/local/php-7.2.33/lib/php/extensions/no-debug-zts-20170718/"
                    (경로는 다 다릅니다.)
date.timezone = Asia/Seoul
expose_php = Off

post_max_size = 500M
upload_max_filesize = 200M
memory_limit = 512M



아래 3개 모듈의 추가 내용을 입력 합니다.


[mcrypt]
extension=mcrypt.so

[opcache]

zend_extension=opcache.so
opcache.enable=1
opcache.memory_consumption=192
    ; 단위는 MB 이며 default는 7.0 부터 128MB 입니다(이전은 64MB)
    ; 192 는 예시임으로 꼭 같게 하지 않아도 됩니다
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.revalidate_path=1
opcache.dups_fix=1
opcache.fast_shutdown=1
opcache.enable_file_override=1
opcache.enable_cli=0


[imagick]

extension=imagick.so




[참고] 
OpCache는 PHP 5.5 버전 부터 기본에 포함 되었으며 이전에는 zend optimizer
를 별도로 설치 및 plugin 하여 사용 하였습니다.
 

사용 용도는 컴파일 / 실행 / 결과 의 순으로 처리되는 PHP에 대해서 Opcache(예전의 Zend Optimizer)를 이용하여 컴파일된 PHP 코드를 메모리에 Cache 해서 접속요청에 더 빠르게 응답을 줄수 있는 기능 입니다







php-fpm 설정



필요 디렉토리 생성 및 설정

[root]# mkdir -p /var/log/php-fpm/
->  로그가 생성될 디렉토리를 생성 합니다.




# Socket Directory 생성 및 tmpdir 관련 설정
[root]# mkdir -p /run/php/
-> socket 이 생성될 디렉토리를 생성 해줍니다.


재부팅 후에 디렉토리가 생성될 수 있도록 tmpfiles 에 설정 합니다.

[root]# cd /usr/lib/tmpfiles.d
[root]# vi php.conf

d /run/php 0755 root root -

--> php.conf 파일에 내용 입력






php-fpm.conf 설정

그다음 공통 파일인 php-fpm.conf 를 설정 하겠습니다.


# php-fpm.conf 파일 생성
[root]# cd /usr/local/php-7.2.33/etc
[root]# cp php-fpm.conf.default php-fpm.conf



# php-fpm.conf 파일 수정
[root]# vi php-fpm.conf

pid = run/php-fpm.pid
-> 주석제거

error_log = /var/log/php-fpm/error.log
-> 주석제거, 수정

; Log level

; Possible Values: alert, error, warning, notice, debug
; Default Value: notice
log_level = debug
-> 설정시 접속 관련 debug 을 위해 설정한  것으로 default로 하여도 됩니다.

daemonize = yes

-> 주석 해제

include=/usr/local/php-7.2.33/etc/php-fpm.d/*.conf

-> 주석제거, 수정







PHP-FPM Pool 설정 

[root]# cd /usr/local/php-7.2.33/etc/php-fpm.d

[root]# cp www.conf.default sitename.conf

[root]# vi sitename.conf

[www]
--> 주석제거, 내용변경
--> pool 이름은 지정하면 됩니다.



user = apache

group = apache
--> 주석제거, php-fpm 을 기동할 유저 및 그룹 지정 

listen.owner = apache
listen.group = apache
listen.mode = 0660
--> 주석제거, php-fpm.sock 파일에 대한 ownership 및 permission 설정






[IP 접속 방식과 UDS]

php-fpm 을 사용시 접속 방법은 크게 2가지 방법으로 사용 할 수 있습니다.
IP 방식과 UDS 라는 Unix Domain Socket 으로 .sock 파일을 이용 하는 것입니다.

1) Apache 혹은 Nginx 와 PHP-FPM을 서버 한곳에서 같이 사용하는 환경이라면 UDS 로 사용하는 부분이 조금더 편하게 프로세스 간의 통신으로 사용 할 수 있습니다

물론 같은 서버내에서 사용하는 환경이라도 IP 방식으로 사용 할 수 있습니다.
UDS 혹은 IP 방식으로 사용 할지를 선택하여 사용 하시면 됩니다.


2) Apache 혹은 Nginx 와 PHP-FPM 을 서버를 분리 하여 각각 사용 하는 환경이라면 IP접속 방식을 사용 해야 합니다.





listen 설정

1) UDS를 사용 할 경우
listen = /var/run/php-fpm/php-fpm.sock
 --> 같은 서버내에서 사용하는 보통의 환경에서는 UDS 로 사용하시면 됩니다.

2) IP 를 사용 할 경우 
listen = 9000

--> 같은 서버내에서 사용하는 보통의 환경에서는 127.0.0.1:9000 으로 사용하여 됩니다
--> 저는 다른 서버에서 접속하는 환경으로 사용할 예정으로 포트만 기재하여 모든곳에서 다 접속이 가능하도록 설정 하도록 하겠습니다.






php-fpm 프로세스 조정

pm 으로 시작하는 파라미터5개와 연관되어 있습니다.

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 40
pm.max_requests = 500

pm.max_children 는 설정된 PHP Pool(여기서는 www) 내에서 가동할 수 있는 최대 자식 프로세스 수를 의미 합니다

pm.start_servers 는 php-fpm 을 실행할 때 초기에 생성하는 자식 프로세스의 개수입니다

pm.min_spare_servers 는 idle 상태의 자식 프로세스 개수가 이 개수보다 작으면 자식 프로세스를 생성합니다

pm.max_spare_servers 는 idle 상태의 자식 프로세스의 최대 개수를 의미 합니다.

pm.max_requests 는 각 프로세스가 최대 request를 처리하면 수 입니다.

500 으로 설정되어 있다면 500번 request 후 프로세스를 다시 생성 합니다

프로세스가 점진적인 메모리 증가에 대한부분을 방지 할 수 있습니다.

apache 에서 유사한 설정으로는 MaxRequestsPerChild 있습니다.






로그 관련 설정

access.log = /var/log/php-fpm/$pool.access.log
--> 주석제거, 경로 변경

access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
--> 주석제거 

slowlog = /var/log/php-fpm/$pool.log.slow
--> 주석제거, 경로 변경

request_slowlog_timeout = 1
--> 주석제거, 내용변경
--> 값은 변경 하여 사용해도 됩니다.

catch_workers_output = yes
-> 주석 해제

php_admin_value[error_log] = /var/log/fpm-php/$pool.error.log

--> 주석제거, 경로 변경

php_admin_flag[log_errors] = on

--> 주석제거






추가 OS 변경 내역



3개의 서버를 이용하여 3-Tier 환경으로 구성 하였으며,1번 노드는 apache httpd   , 2번은 mysql  , 3번 노드는 php-fpm 으로 구성하였습니다.

서버가 여러개로 나워져있으므로 firewall , /etc/hosts 등의 추가적인 설정을 진행하도록 하겠습니다.
먼저 각 서버간의 설정 및 접속을 편하게 하기 위해 저는 /etc/hosts 에 등록하여 사용하였습니다.


[참고] 같은 서버내에서 구성할 경우 이 단계는 생략 하고 다음(아래) 단계로 이동하시면 됩니다.




# vi /etc/hosts

123.123.123.101 node1

123.123.123.102 node2
123.123.123.103 node3

 * node , ip 등은 모두 예시 입니다.

 * 이 작업은 필수는 아닙니다.





MySQL DB 포트 오픈

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address=123.123.123.103 port port="3306" protocol="tcp" accept'





php-fpm 포트 오픈

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address=123.123.123.101 port port="9000" protocol="tcp" accept'




Firewall적용 및 확인

firewall-cmd --reload ; firewall-cmd --list-all






필요에 따라 db user의 host의 변경

(필요에 따라, 구성에 따라 다름)

mysql> update mysql.user set host='123.123.123.103'
              where user='dbuser' and host='123.123.123.101';
mysql> commit;
myslq > flush privileges;




대부분 설정 블로그나 웹 문서가 같은 서버내에서 구성으로 되어 있으며 별도의 서버로 분리하여 설정한 내용을 찾기가 어려워서 php 웹 소스를 어느서버에 있어야 하는지에 대한 부분은 테스트를 통해 Apache가 있어야 하는 web서버 와 php-fpm 이 구동되어 있는 서버에도 같이 있어야 하는 결론을 내렸습니다

소스를 각각 관리 하는 어려움이 있어서 nfs나 rsync 등을 고려 하였으나 보안상 그리고 파일이 첨부되거나 변경되는 사항에 대해서 바로 적용 되어 사용할수 있도록 내부 간 통신임으로 sshfs를 통해 파일시스템을 마운트 해서 사용 했습니다.







php-fpm 서비스 등록 및 기동



PHP Source 에서 파일을 복사 후 서비스를 등록 합니다.

[root]# cd /root/source/php-7.2.33/sapi/fpm

[root]# cp php-fpm.service /etc/systemd/system/php-fpm.service

[root]# systemctl daemon-reload
[root]# systemctl enable php-fpm
[root]# systemctl start php-fpm







apache 설정 및 재기동



httpd.conf 파일 수정

[root]# vi /usr/local/apache2.4/conf/httpd.conf


먼저 기존에 php module이 로딩되어 있다면 주석 처리 합니다
#LoadModule php5_module modules/libphp5.so





virtualhost 를 사용한다면 <virtualhost> </virtualhost> 사이에 Proxy 내용을 추가 합니다
virtualhost 를 사용하지 않으면 편하신 곳에 아래의 proxy 설정 내용을 입력 합니다.



php-fpm-pool 의 listen 에 따라서 이부분도 설정이 달라 지게 됩니다.





1) listen 을 UDS 방식으로 설정하여 사용시


listen = /var/run/php-fpm/php-fpm.sock

=> ProxtPassMatch 구문을 아래와 같이 사용 하면 됩니다.
=> socket 파일이 각 시스템의 설정과 맞는지 확인 합니다.
ProxyRequests Off
ProxyPreserveHost On
ProxyErrorOverride on
ProxyTimeout 600
 <FilesMatch \.(php|phar)$>
      SetHandler "proxy:unix:/run/php/php-fpm.sock|fcgi://localhost"
</FilesMatch>
-> SetHandler 절에 파일명은 위에서 설정한 PHP-FPM의 Socket의 경로와 파일명이 같아야 합니다
-> PHP-FPM : listen=/run/php/php-fpm.sock 사용시




2) listen 을 IP 방식으로 설정시

listen = 9000


=> 아래와 같이 사용 하시면 됩니다.
ProxyRequests Off

ProxyPreserveHost On
ProxyErrorOverride on
ProxyTimeout 600
<FilesMatch \.(php|phar)$>
     SetHandler "proxy:fcgi://node3:9000"
</FilesMatch>

node3:9000
이부분은 php-fpm 에서 설정한 IP 혹은 사용중인 호스트명과 설정한 포트번호를 입력 합니다.

-> PHP-FPM : listen = 127.0.0.1:9000 이나 listen = 9000 사용시




설정이 완료 되었다면 저장 후 apache를 재기동이나 reload(graceful)  을 합니다

[root]# systemctl restart httpd
or
[root]# systemctl reload httpd


php 로 구성된 사이트가 정상접속 되는지, 로그에 특이사항이 있는지를 마지막으로 체크 합니다.




이어지는 글
웹 기반 mysql 관리툴 - phpmyadmin 설치 및 설정

Apache 2.4 에 웹 방화벽인 ModSecurity 구성




연관된 글
proxy_balancer 를 이용한 PHP-FPM 다중화 - 로드 발란스 구성

PHP 7.4 소스컴파일(Source Compile) 설치

PHP 8.0 출시 소식 과 8.0 설치 진행 내역

 

“APM - Apache 와 PHP-FPM 설치 연동” 에 대한 3 댓글

  1. 안녕하세요
    저는 httpd와 php-fpm을 분리하는 테스트를 하고 있습니다.
    각각 컨테이너로 구성이 되어있고
    작성해주신 글을 보면서 listen 설정으로 연동(?)은 된 것 같습니다
    httpd쪽에서 php파일을 열게 될 경우 php-fpm쪽 root directory에도 php파일이 존재해야하는데
    php-fpm의 root directory가 어디인지 도무지 알 수 가 없네요 ㅠㅠ
    tomcat은 root directory가 있어서 설정이 가능한데 php-fpm은 제가 잘 모르는건지 싶네요..

    1. 안녕하세요
      httpd 와 php-fpm 이 물리적 서버로 분리되어있거나 또는 컨테이너로 분리 되어있을 경우
      경로를 동일 하게 맞춰주시고 파일을 위치시켜주시면 됩니다.

      감사합니다.

답글 남기기