Docker DevOps Kubernetes

[Deploy Php Trên K8s] phần 1: Xây dựng image php-fpm docker

k8s

Như chúng ta đã biết, Php là một trong những ngôn ngữ lập trình website khá phổ biến hiện nay. Trong bài hướng dẫn này,  tôi sẽ hướng dẫn các bạn có thể tự mình build image và triển khai nó trên K8s, một công cụ quản lý container khá nổi tiếng trong thời gian gần đây. 

Nội dung xoay quanh trong bài này, chúng ta sẽ tìm hiểu cách để build được một image docker để có thể chạy được PHP. Tôi giả sử bạn đã cài đặt Docker trước đó rồi nha. Các bạn có thể tham khảo trang chủ Docker để biết cách cài đặt. 

Bước 1: Tạo một Dockerfile với nội dung như sau:

FROM ubuntu:18.04 
ENV TZ=Asia/Ho_Chi_Minh
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y \
&&  apt-get install -y software-properties-common  \
&& add-apt-repository ppa:ondrej/php -y \
&& apt-get update -y && apt-get install -y nginx supervisor tzdata \
php5.6 php5.6-mbstring php5.6-mcrypt php5.6-mysql php5.6-xml \
php5.6-fpm php5.6-cli php5.6-curl php5.6-gd   php5.6-imap \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
&& dpkg-reconfigure --frontend noninteractive tzdata \
&& mkdir -p /var/www/html  /var/log/supervisor/  /run/php \
&&  touch /var/www/html/info.php \
&& sed -i "s/\;cgi\.fix\_pathinfo\=1/cgi\.fix\_pathinfo\=0/g" /etc/php/5.6/fpm/php.ini \
&& sed -i "s/listen\ =\ \/run\/php\/php5\.6\-fpm\.sock/listen\ =\ 0.0.0.0:9000/g" /etc/php/5.6/fpm/pool.d/www.conf \
&& sed -i 's/disable_functions\ \=.*/disable_functions\ \=\ pcntl_alarm,pcntl_fork,pcntl_waitpid,\
pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,\
pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,\
pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,\
pcntl_getpriority,pcntl_setpriority,phpinfo,system,mail,exec,passthru,shell_exec,\
system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,/g' /etc/php/5.6/fpm/php.ini \
&& sed -i 's/expose_php\ \=.*/expose_php\ \=\ Off/g' /etc/php/5.6/fpm/php.ini \
&& sed -i 's/allow_url_include\ \=.*/allow_url_include\ \=\ Off/g' /etc/php/5.6/fpm/php.ini \
&& sed -i "s/pm.max_children\ \=.*/pm.max_children\ \=\ 5/g" /etc/php/5.6/fpm/pool.d/www.conf \
&& sed -i "s/pm.start_servers\ \=.*/pm.start_servers\ \=\ 2/g" /etc/php/5.6/fpm/pool.d/www.conf \
&& sed -i "s/pm.min_spare_servers\ \=.*/pm.min_spare_servers\ \=\ 2/g" /etc/php/5.6/fpm/pool.d/www.conf \
&& sed -i "s/pm.max_spare_servers\ \=.*/pm.max_spare_servers\ \=\ 4/g" /etc/php/5.6/fpm/pool.d/www.conf \
&& echo '\n\
user www-data;\n\
worker_processes 1;\n\
pid /run/nginx.pid;\n\
events {\n\
        worker_connections 1024;\n\
        multi_accept on;\n\
}\n\
http {\n\
        sendfile on;\n\
        tcp_nopush on;\n\
        tcp_nodelay on;\n\
        keepalive_timeout 65;\n\
        types_hash_max_size 2048;\n\
        server_tokens off;\n\
        include /etc/nginx/mime.types;\n\
        default_type application/octet-stream;\n\
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n\
        access_log /var/log/nginx/access.log;\n\
        error_log /var/log/nginx/error.log;\n\
        gzip on;\n\
        gzip_disable "msie6";\n\
        fastcgi_cache_path /dev/shm/cache levels=1:2 keys_zone=my-zone:800m inactive=60m;\n\
        fastcgi_cache_key "$scheme$request_method$host$request_uri";\n\
        fastcgi_cache_lock on;\n\
        fastcgi_cache_use_stale error timeout invalid_header updating http_500;\n\
        fastcgi_cache_valid 5m;\n\
        fastcgi_ignore_headers Cache-Control Expires Set-Cookie;\n\
        include /etc/nginx/sites-enabled/*.conf;\n\
}\n\
' > /etc/nginx/nginx.conf \
&& echo '\n\
server {\n\
	listen 80 default_server;\n\
	listen [::]:80 default_server;\n\
        access_log /var/log/nginx/app.access.log;\n\
        error_log /var/log/nginx/app.error.log;\n\
	root /var/www/html/;\n\
\n\
	index index.php index.html  index.htm index.nginx-debian.html;\n\
	add_header X-Cache $upstream_cache_status;\n\
	server_name _;\n\
\n\
	location / {\n\
		# First attempt to serve request as file, then\n\
		# as directory, then fall back to displaying a 404.\n\
		try_files $uri $uri/ /index.php?$args;\n\
	}\n\
	# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000\n\
	#\n\
	location ~ \.php$ {\n\
		include snippets/fastcgi-php.conf;\n\
		fastcgi_split_path_info ^(.+\.php)(/.+)$;\n\
		#fastcgi_pass unix:/run/php/php5.6-fpm.sock;\n\
		fastcgi_pass 127.0.0.1:9000;\n\
		fastcgi_buffer_size 512k;\n\
		fastcgi_buffers 512 64k;\n\
		fastcgi_send_timeout 3000;\n\
		fastcgi_read_timeout 3000;\n\
	}\n\
	# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000\n\
        #\n\
        location ~* /(?:uploads|files|wp-content|wp-includes)/.*\.php$\n\
        {\n\
                deny all;\n\
        }\n\
\n\
        location ~ /(\.|wp-config.php|readme.html|license.txt) { deny all; }\n\
        location ~* \.(pl|cgi|py|sh|lua)\$\n\
        {\n\
                return 444;\n\
        }\n\
        location ~* \.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$|\.php_\n\
        {\n\
                return 444;\n\
        }\n\
        location ~* (roundcube|webdav|smtp|http\:|soap|w00tw00t|wp-json)\n\
        {\n\
                return 444;\n\
        }\n\
        location ~ \.php$ {\n\
                include snippets/fastcgi-php.conf;\n\
                fastcgi_split_path_info ^(.+\.php)(/.+)$;\n\
                fastcgi_pass 127.0.0.1:9000;\n\
                fastcgi_read_timeout 300;\n\
                fastcgi_buffer_size 512k;\n\
                fastcgi_buffers 512 64k;\n\
        }\n\
        ## Block SQL injections\n\
        set $block_sql_injections 0;\n\
        if ($query_string ~ "union.*select.*\(") {\n\
                set $block_sql_injections 1;\n\
        }\n\
        if ($query_string ~ "union.*all.*select.*") {\n\
                set $block_sql_injections 1;\n\
        }\n\
        if ($query_string ~ "concat.*\(") {\n\
                set $block_sql_injections 1;\n\
        }\n\
        if ($block_sql_injections = 1) {\n\
                return 403;\n\
        }\n\
\n\
        ## Block file injections\n\
        set $block_file_injections 0;\n\
        if ($query_string ~ "[a-zA-Z0-9_]=http://") {\n\
                set $block_file_injections 1;\n\
        }\n\
        if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") {\n\
                set $block_file_injections 1;\n\
        }\n\
        if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") {\n\
                set $block_file_injections 1;\n\
        }\n\
        if ($block_file_injections = 1) {\n\
                return 403;\n\
        }\n\

        ## Block common exploits\n\
        set $block_common_exploits 0;\n\
        if ($query_string ~ "(<|%3C).*script.*(>|%3E)") {\n\
                set $block_common_exploits 1;\n\
        }\n\
        if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") {\n\
                set $block_common_exploits 1;\n\
        }\n\
        if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") {\n\
                set $block_common_exploits 1;\n\
        }\n\
        if ($query_string ~ "proc/self/environ") {\n\
                set $block_common_exploits 1;\n\
        }\n\
        if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") {\n\
                set $block_common_exploits 1;\n\
        }\n\
        if ($query_string ~ "base64_(en|de)code\(.*\)") {\n\
                set $block_common_exploits 1;\n\
        }\n\
        if ($block_common_exploits = 1) {\n\
                return 403;\n\
        }\n\
        ## Block spam\n\
        set $block_spam 0;\n\
        if ($query_string ~ "\b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)\b") {\n\
                set $block_spam 1;\n\
        }\n\
        if ($query_string ~ "\b(erections|hoodia|huronriveracres|impotence|levitra|libido)\b") {\n\
                set $block_spam 1;\n\
        }\n\
        if ($query_string ~ "\b(ambien|blue\spill|cialis|cocaine|ejaculation|erectile)\b") {\n\
                set $block_spam 1;\n\
        }\n\
        if ($query_string ~ "\b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)\b") {\n\
                set $block_spam 1;\n\
        }\n\
        if ($block_spam = 1) {\n\
                return 403;\n\
        }\n\
        ## Block user agents\n\
        set $block_user_agents 0;\n\
        # Disable Akeeba Remote Control 2.5 and earlier\n\
        if ($http_user_agent ~ "Indy Library") {\n\
                set $block_user_agents 1;\n\
        }\n\
        # Common bandwidth hoggers and hacking tools.\n\
        if ($http_user_agent ~ "libwww-perl") {\n\
                set $block_user_agents 1;\n\
        }\n\
        if ($http_user_agent ~ "GetRight") {\n\
                set $block_user_agents 1;\n\
        }\n\
        if ($http_user_agent ~ "GetWeb!") {\n\
                set $block_user_agents 1;\n\
        }\n\
        if ($http_user_agent ~ "Go!Zilla") {\n\
                set $block_user_agents 1;\n\
        }\n\
        if ($http_user_agent ~ "Download Demon") {\n\
                set $block_user_agents 1;\n\
        }\n\
        if ($http_user_agent ~ "Go-Ahead-Got-It") {\n\
                set $block_user_agents 1;\n\
        }\n\
        if ($http_user_agent ~ "TurnitinBot") {\n\
                set $block_user_agents 1;\n\
        }\n\
        if ($http_user_agent ~ "GrabNet") {\n\
                set $block_user_agents 1;\n\
        }\n\
        if ($block_user_agents = 1) {\n\
                return 403;\n\
        }\n\
        location ~ /\.ht {\n\
                deny all;\n\
        }\n\
}\n\
' > /etc/nginx/sites-enabled/app.conf \
&&  echo '\n\
[program:nginx]\n\
command=nginx -c /etc/nginx/nginx.conf -g "daemon off;"\n\
autostart=true\n\
autorestart=true\n\
redirect_stderr=true\n\
stdout_logfile=/var/log/supervisor/nginx_out.log\n\
\n\
[program:php-fpm]\n\
command=php-fpm5.6 -R -F -c /etc/php/5.6/fpm/php-fpm.conf\n\
autostart=true\n\
autorestart=true\n\
redirect_stderr=true\n\
stdout_logfile=/var/log/supervisor/php-fpm.out.log\n\
stderr_logfile=/var/log/supervisor/php-fpm.err.log\n\
' >>  /etc/supervisor/supervisord.conf \
&& echo '\n\
<?php\n\
phpinfo();\n\
phpinfo(INFO_MODULES);\n\
?>\n\
' > /var/www/html/info.php

EXPOSE 80
ADD entrypoint.sh /entrypoint.sh
#ADD html  /var/www/html
#RUN chown -R www-data:www-data /var/www/html
CMD [ "/bin/bash","/entrypoint.sh" ]

Bước 2: tạo file entrypoint.sh trong cùng một thư mục với Dockerfile, với nội dung:

#!/bin/sh
set -e
supervisord -n -c /etc/supervisor/supervisord.conf
wait $!

Trong Dockerfile này, tôi đã configure một vài thông số để đảm bảo tính an toàn thông tin cho application, điển hình là chặn quyền thực thi của php, chặn sql injection, caching .v.v..  Bạn có thể tùy chỉnh bổ sung, phù hợp với nhu cầu sử dụng của bạn.

Bước 3: Tiến hành build images

docker build -t php-fpm .

Đợi vài phút cho để Docker tiến hành build images.

Chúc các bạn thành công !!

Người Viết:
LK

 

Đăng ký liền tay Nhận Ngay Bài Mới

Subscribe ngay

Cám ơn bạn đã đăng ký !

Lỗi đăng ký !

Add Comment

Click here to post a comment

Đăng ký liền tay
Nhận Ngay Bài Mới

Subscribe ngay

Cám ơn bạn đã đăng ký !

Lỗi đăng ký !