Herkese selam, uzun zamandır PHP projelerimde kullanmak için hazırladığım bir Dockerfile dosyam vardı. PHP 8.3 için bazı güncellemeler ve eklemeler yaparak paylaşmaya karar verdim. İçinde hem API projelerinizde ihtiyacınız olabilecekler hem de UI barındıran projeler geliştirmek için ihtiyacınız olabilecek uygulamalar mevcut.
PostgreSQL, Redis, Kafka, MongoDB, Swoole / OpenSwoole ve XDebug olmak üzere ihtiyacımız olan temel diğer tüm yazılımlar mevcut. Ek olarak gRPC, Protobuf ve Apache SkyWalking ekledim ve Locale ayarlarını Türkçe ile uyumlu hale getirdim.
Ortam olarak PHP-FPM kullandığım için FPM ayarlarını özellikle kendime göre değiştirdim. Eğer sadece API olarak kullanacaksanız php-fpm.conf
dosyasında gerekli değişikliği yaparak gereksiz izinleri kaldırmanızda fayda var.
Image oluştuğu zaman 900MB civarında oluyor ve tamamlanma süresi bilgisayarınızın hızına göre ~10dk veya üzerine çıkabiliyor.
Sadece Dockerfile değil birkaç ek dosya daha paylaşacağım için şimdiden bir klasör düzeni oluşturmakta fayda var. Bu klasör yapısını oluşturursanız kolaylıkla build alabilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 |
➜ PHP83 tree . ├── Dockerfile ├── build.sh ├── config │ ├── 999-extra.ini │ ├── cacert.ini │ ├── php-fpm.conf │ ├── php-fpm.ini │ └── skywalking.ini └── test.sh |
Dosyalarınızı aynı bu düzende kaydetmeye çalışın.
Dockerfile ile başlayalım. Bu içeriği dosya uzantısı olmadan sadece Dockerfile
ismiyle oluşturduğunuz klasörün içine kaydedin.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# 1. Adım : Build işlemleri için base image oluşturuluyor FROM php:8.3.3-fpm AS build_apache_skywalking WORKDIR /var/www/ RUN rm -rf /var/www/* ENV GIT_TRACE_PACKET=1 ENV GIT_TRACE=1 ENV GIT_CURL_VERBOSE=1 ENV BUILD_FOLDER_NAME=___build RUN mkdir $BUILD_FOLDER_NAME WORKDIR /var/www/$BUILD_FOLDER_NAME RUN true \ ########## Apache SkyWalking # https://skywalking.apache.org/docs/skywalking-php/next/en/setup/service-agent/php-agent/readme/ # 1. Build edilebilmesi için "cargo" yüklü olmalı && export CARGO_NET_GIT_FETCH_WITH_CLI=true \ && apt-get update -y \ && apt-get install -y git gnutls-bin wget \ && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rust.sh \ && chmod +x rust.sh \ && sh ./rust.sh -y \ && export PATH="$HOME/.cargo/bin:$PATH" \ && touch $HOME/.cargo/config.toml \ && echo '[net]\nretry = 3\ngit-fetch-with-cli = true' > $HOME/.cargo/config.toml \ # 2. SkyWalking && apt install -y gcc make llvm-13-dev libclang-13-dev protobuf-c-compiler protobuf-compiler \ && pecl install --configureoptions 'enable-cargo-debug="no" enable-kafka-reporter="yes"' skywalking_agent \ # 3. Oluşturulan dosyalar dışarı alınıyor && CURRENT_BUILD=$(ls -td -- /usr/local/lib/php/extensions/* | head -n 1) \ && cp $CURRENT_BUILD/skywalking_agent.so /var/www \ # 4. Yüklenen paketler siliniyor && rustup self uninstall -y \ && (apt-get remove -y --auto-remove rust cargo | true) \ && (apt-get purge -y cargo | true) \ && (apt remove -y llvm-13-dev libclang-13-dev | true) \ && rm -rf ~/.cargo \ ########## Genel Temizlik Yapılıyor.. && apt-get autoclean && apt-get clean \ && apt-get clean autoclean && apt-get -y autoremove && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* \ && cd /var/www \ && rm -rf $BUILD_FOLDER_NAME WORKDIR /var/www # 2. Adım : PHP 8.3 için image oluşturuluyor # pthreads requires a build of PHP with ZTS (Zend Thread Safety) enabled ( --enable-maintainer-zts or --enable-zts on Windows ) # FPM is a "process" manager, and don't need thread safety, by design. Server load is shared between the processes. FROM php:8.3.3-fpm AS php MAINTAINER Sakir Mehmetoglu <sakir.mehmetoglu@gmail.com> ARG TIMEZONE=Europe/Istanbul ARG DEBIAN_FRONTEND=noninteractive ENV COMPOSER_ALLOW_SUPERUSER=1 ENV LC_ALL tr_TR.UTF-8 ENV LANG tr_TR.UTF-8 ENV LANGUAGE=$LANG ENV ENV_TIMEZONE=$TIMEZONE # Projenin konumu belirleniyor WORKDIR /var/www RUN rm -rf /var/www/* # Gerekli Kaynaklar Hazırlanıyor.. ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ RUN chmod +x /usr/local/bin/install-php-extensions && sync # Tüm kurulum işlemleri yapılıyor RUN \ # Temizlik Yapılıyor.. apt-get clean autoclean && apt-get -y autoremove && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* \ \ # Güncelleme Yapılıyor.. && apt-get update -y \ \ # PHP Kütüphanelerinin Kurulması İçin Gerekli Hazırlık Yapılıyor.. && chmod +x /usr/local/bin/install-php-extensions && sync \ \ # Gerekli Yazılımlar Kuruluyor.. && apt-get install -y \ procps \ iputils-ping \ telnet \ openssl \ libcurl4-gnutls-dev \ build-essential \ libpng-dev \ libjpeg62-turbo-dev \ libfreetype6-dev \ libonig-dev \ jpegoptim optipng pngquant gifsicle \ vim \ git \ nano \ gnupg \ libssl-dev \ apt-utils \ libsodium-dev \ gosu \ ca-certificates \ apt-transport-https \ lsb-release \ supervisor \ sqlite3 \ libcap2-bin \ default-mysql-client \ # cgi-fcgi - FASTCgi (fcgi) is a language independent, high performant extension to CGI libfcgi0ldbl \ \ # Zip && apt-get -y install libzip-dev zip unzip && docker-php-ext-configure zip && docker-php-ext-install zip \ \ ## PHP İçin Gerekli Kurulumlar Yapılıyor && install-php-extensions curl exif mbstring \ \ # ImageMagick # https://github.com/freekmurze/freek-dev-comments/issues/59#issuecomment-803560832 #&& apt-get install -y imagemagick libmagickwand-dev libmagickcore-dev \ \ # Curl && apt-get install -y libcurl4-dev curl && docker-php-ext-install curl \ \ # GD && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng-dev && docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ && docker-php-ext-install gd \ \ # Locales (https://stackoverflow.com/a/55077451) && echo "LC_ALL=$LC_ALL" >> /etc/environment && echo "tr_TR.UTF-8 UTF-8" >> /etc/locale.gen && echo "LANG=$LANG" > /etc/locale.conf \ && apt-get update -y && apt-get install -y locales && locale-gen $LANG && dpkg-reconfigure locales \ \ # Timezone \ && ln -fs /usr/share/zoneinfo/$ENV_TIMEZONE /etc/localtime \ \ # Human Language and Character Encoding Support # Install PHP extensions intl (intl requires to be configured) \ # Install icu dev libs support && apt-get install -y zlib1g-dev libicu-dev g++ && docker-php-ext-configure intl && docker-php-ext-install intl \ \ # BC Math && docker-php-ext-install bcmath \ \ # PCNTL (Process Control Extensions) && docker-php-ext-configure pcntl --enable-pcntl && docker-php-ext-install pcntl \ \ # PDO, MySQL && docker-php-ext-install pdo mysqli pdo_mysql && docker-php-ext-enable pdo_mysql \ # PostgreSQL - Postgres/pgsql && apt-get install -y libpq-dev && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql && docker-php-ext-install pdo_pgsql pgsql \ \ # Protobuf && apt-get install -y protobuf-compiler protobuf-compiler-grpcM \ \ # Redis && install-php-extensions redis \ # Kafka && install-php-extensions rdkafka \ # MongoDB && install-php-extensions mongodb \ # Swoole, OpenSwoole && install-php-extensions swoole \ # && install-php-extensions openswoole \ # xDebug && install-php-extensions xdebug \ # GRPC && install-php-extensions grpc \ # Protocol Buffers - protobuf && install-php-extensions protobuf \ # Let's Encrypt && install-php-extensions @fix_letsencrypt \ # Temizlik Yapılıyor.. && apt-get clean autoclean && apt-get -y autoremove && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* # Composer yükleniyor.. COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer # Apache SkyWalking yükleniyor.. COPY --from=build_apache_skywalking /var/www/skywalking_agent.so . RUN CURRENT_BUILD=$(ls -td -- /usr/local/lib/php/extensions/* | head -n 1) && mv skywalking_agent.so $CURRENT_BUILD COPY ./config/php-fpm.ini /usr/local/etc/php/conf.d/php.ini COPY ./config/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf COPY ./config/skywalking.ini /usr/local/etc/php/conf.d/skywalking.ini # COPY ./config/cacert.ini /usr/local/etc/php/conf.d/cacert.ini # COPY ./config/999-extra.ini /usr/local/etc/php/conf.d/999-extra.ini RUN echo '<?php\n\nphpinfo();\n' > index.php |
Bu Dockerfile dosyasının yanına build.sh
adında bir dosya daha oluşturun ve içeriğine aşağıdakileri ekleyin.
1 2 3 |
docker build -t sustartx/php-fpm-83 -f Dockerfile . # docker buildx build --platform linux/amd64 -t sustartx/php-fpm-83 -f Dockerfile . # docker buildx build --platform linux/amd64,linux/arm64 -t sustartx/php-fpm-83 -f Dockerfile . |
Bu dosyada build almak istediğiniz platforma özel değişiklikler yapabilmeniz için bazı örnekler de ekledim.
Aynı klasörde test.sh
adında bir dosya daha oluşturun ve içeriğini ekleyin.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#!/bin/sh set -e # https://www.inanzzz.com/index.php/post/653v/testing-php-fpm-without-having-a-web-server process_id=$(docker run -d sustartx/php-fpm-83:latest) CMD="sleep 0.5 && SCRIPT_FILENAME=/var/www/index.php REQUEST_METHOD=GET cgi-fcgi -bind -connect localhost:9000" html_content=$(docker exec -t $process_id sh -c "$CMD") # PHP sürümü tespit ediliyor.. php_version_search_text_1='<tr><td class="e">PHP Version </td><td class="v">([0-9]+\.[0-9]+\.[0-9]+) </td></tr>' php_version_search_text_2='<tr><td class="e">PHP_VERSION </td><td class="v">([0-9]+\.[0-9]+\.[0-9]+) </td></tr>' regex_result=$(echo "$html_content" | grep -oE "$php_version_search_text_1|$php_version_search_text_2" | uniq) if [ -n "$regex_result" ]; then php_version=$(echo "$regex_result" | grep -oE "[0-9]+\.[0-9]+\.[0-9]+" | head -n 1) else php_version="Not Found !" fi echo "PHP : $php_version" # Apache SkyWalking sürümü tespit ediliyor.. search_text='<tr><td class="e">skywalking_agent.enable</td><td class="v">1</td><td class="v">1</td></tr>' ApacheSkyWalkingStatus=$(echo "$html_content" | grep -qF "$search_text" && echo "Apache SkyWalking Enabled !" || echo "Apache SkyWalking Disabled Or Not Found !") echo "$ApacheSkyWalkingStatus" docker stop $process_id > /dev/null 2>&1 docker rm $process_id > /dev/null 2>&1 |
Özellikle bu dosya beni biraz fazla uğraştırmıştı. PHP-FPM kullandığım için böyle bir test dosyası yazmak zorunda kaldım. Kaynak olarak kullandığım adresi de dosya içinde bulabilirsiniz. İlgili içeriği takip ederek daha farklı testler de oluşturabilirsiniz.
Sıra geldi diğer dosyalarımıza. Şimdi config
adında bir klasör oluşturun ve bundan sonraki dosyaları bu klasör içinde oluşturarak devam edin.
İlk olarak php-fpm.conf
dosyamızı oluşturalım.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
[www] user = www-data group = www-data listen = 127.0.0.1:9000 pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 ; Aşağıdaki listeden dosya uzantıları alınarak content-type için liste oluşturuldu. Oluşturulan listedeki dosya uzantıları buraya da kopyalandı. ; https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types security.limit_extensions = .php .aac .abw .arc .avif .avi .azw .bin .bmp .bz .bz2 .cda .csh .css .csv .doc .docx .eot .epub .gz .gif .htm .html .ico .ics .jar .jpeg .jpg .jfif .pjpeg .pjp .js .json .jsonld .mid .midi .mjs .mp3 .mp4 .mpeg .mpkg .odp .ods .odt .oga .ogv .ogx .opus .otf .png .apng .pdf .php .ppt .pptx .rar .rtf .sh .svg .swf .tar .tif .tiff .ts .ttf .txt .vsd .wav .weba .webm .webp .woff .woff2 .xhtml .xls .xlsx .xml .xul .zip .7z .map catch_workers_output = yes ; https://www.inanzzz.com/index.php/post/653v/testing-php-fpm-without-having-a-web-server pm.status_path=/status ping.path=/ping ping.response=pong php_flag[display_errors] = on php_admin_value[error_log] = /var/log/fpm-php.www.log php_admin_flag[log_errors] = on |
Gördüğünüz gibi bir hayli kalabalık görünüyor. Burada kendi ihtiyaçlarınıza göre security.limit_extensions
içeriğini değiştirmenizde fayda var. Diğer ayarlar da tamamen sizin ihtiyacınıza göre değiştirilebilir ama test için eklediğim kısımları değiştirmemenizi tavsiye ederim. Eğer bir değişiklik yapacak olursanız test dosyasında da gerekli değişiklikleri yapmayı unutmayınız.
php-fpm.ini
adında dosya oluşturun ve içeriğini aşağıdaki gibi düzenleyin. Mümkün olduğunca üzerinde değişiklik yapmamaya özen gösterdim. Siz kendi ihtiyaçlarınıza göre değiştirebilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
max_input_vars = 1000 engine = On short_open_tag = Off max_execution_time = 30 ; Maximum amount of time each script may spend parsing request data. It's a good idea to limit this time on productions servers in order to eliminate unexpectedly long running scripts. Note: This directive is hardcoded to -1 for the CLI SAPI ; Default Value: -1 (Unlimited) ; Development Value: 60 (60 seconds) ; Production Value: 60 (60 seconds) ; https://php.net/max-input-time max_input_time = 60 memory_limit = 256M error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT display_errors = Off ; This directive determines which super global arrays are registered when PHP starts up. G,P,C,E & S are abbreviations for the following respective super globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty paid for the registration of these arrays and because ENV is not as commonly used as the others, ENV is not recommended on productions servers. You can still get access to the environment variables through getenv() should you need to. ; Default Value: "EGPCS" ; Development Value: "GPCS" ; Production Value: "GPCS"; ; https://php.net/variables-order variables_order = "GPCS" ; This directive determines which super global data (G,P & C) should be registered into the super global array REQUEST. If so, it also determines the order in which that data is registered. The values for this directive are specified in the same manner as the variables_order directive, EXCEPT one. Leaving this value empty will cause PHP to use the value set in the variables_order directive. It does not mean it will leave the super globals array REQUEST empty. ; Default Value: None ; Development Value: "GP" ; Production Value: "GP" ; https://php.net/request-order request_order = "GP" default_charset = "UTF-8" max_file_uploads = 20 ; Maximum allowed size for uploaded files. ; http://php.net/upload-max-filesize upload_max_filesize = 100M ; Maximum size of POST data that PHP will accept. ; Its value may be 0 to disable the limit. It is ignored if POST data reading ; is disabled through enable_post_data_reading. ; http://php.net/post-max-size post_max_size = 100M ; Whether to allow the treatment of URLs (like http:// or ftp://) as files. ; https://php.net/allow-url-fopen allow_url_fopen = On ; Whether to allow include/require to open URLs (like https:// or ftp://) as files. ; https://php.net/allow-url-include allow_url_include = Off ; Default timeout for socket based streams (seconds) ; https://php.net/default-socket-timeout default_socket_timeout = 60 ; Whether to use strict session mode. Strict session mode does not accept an uninitialized session ID, and regenerates the session ID if the browser sends an uninitialized session ID. Strict mode protects applications from session fixation via a session adoption vulnerability. It is disabled by default for maximum compatibility, but enabling it is encouraged. ; https://wiki.php.net/rfc/strict_sessions session.use_strict_mode = 0 ; Whether to use cookies. ; https://php.net/session.use-cookies session.use_cookies = 1 ; https://php.net/session.cookie-secure ;session.cookie_secure = ; This option forces PHP to fetch and use a cookie for storing and maintaining the session id. We encourage this operation as it's very helpful in combating session hijacking when not specifying and managing your own session id. It is not the be-all and end-all of session hijacking defense, but it's a good start. ; https://php.net/session.use-only-cookies session.use_only_cookies = 1 ; Name of the session (used as cookie name). ; https://php.net/session.name session.name = PHPSESSID ; The domain for which the cookie is valid. ; https://php.net/session.cookie-domain session.cookie_domain = ; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. ; https://php.net/session.cookie-httponly session.cookie_httponly = ; Add SameSite attribute to cookie to help mitigate Cross-Site Request Forgery (CSRF/XSRF) Current valid values are "Strict", "Lax" or "None". When using "None", make sure to include the quotes, as `none` is interpreted like `false` in ini files. ; https://tools.ietf.org/html/draft-west-first-party-cookies-07 session.cookie_samesite = ; Document expires after n minutes. ; https://php.net/session.cache-expire session.cache_expire = 180 [curl] ; A default value for the CURLOPT_CAINFO option. This is required to be an absolute path. ;curl.cainfo = [openssl] ; The location of a Certificate Authority (CA) file on the local filesystem to use when verifying the identity of SSL/TLS peers. Most users should not specify a value for this directive as PHP will attempt to use the OS-managed cert stores in its absence. If specified, this value may still be overridden on a per-stream basis via the "cafile" SSL stream context option. ;openssl.cafile= ; If openssl.cafile is not specified or if the CA file is not found, the directory pointed to by openssl.capath is searched for a suitable certificate. This value must be a correctly hashed certificate directory. Most users should not specify a value for this directive as PHP will attempt to use the OS-managed cert stores in its absence. If specified, this value may still be overridden on a per-stream basis via the "capath" SSL stream context option. ;openssl.capath= |
Apache SkyWalking kurulumundan sonra ayarlarını da değiştirebilmemiz için skywalking.ini
dosyasına ihtiyacımız var. Bu içeriği kendi ihtiyacınıza göre değiştirerek kullanabilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# https://skywalking.apache.org/docs/skywalking-php/next/en/setup/service-agent/php-agent/readme/#configure [skywalking_agent] extension = skywalking_agent.so ; Enable skywalking_agent extension or not. skywalking_agent.enable = On ; Log file path. skywalking_agent.log_file = /tmp/skywalking-agent.log ; Log level: one of `OFF`, `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`. skywalking_agent.log_level = INFO ; Address of skywalking oap server. skywalking_agent.server_addr = 127.0.0.1:11800 ; Application service name. skywalking_agent.service_name = hello-skywalking |
CA sertifika yolunu verebilmemiz için cacert.ini
dosyamızı oluşturmayı unutmayalım.
1 |
curl.cainfo = "/certificates/cacert.pem" |
Eğer dikkatli baktıysanız Dockerfile dosyamızda bu dosya image içine koyulmuyor. Siz ihtiyacınıza uygun şekilde değişiklik yaparak işleme devam edebilirsiniz.
Son olarak 999-extra.ini
adında bir dosya oluşturun ve içeriğini ekleyin.
1 2 3 4 5 |
file_uploads = On memory_limit = 100M upload_max_filesize = 10M post_max_size = 10M max_execution_time = 600 |
Burada da gördüğünüz gibi en çok ihtiyacımız olan değişiklikleri yapıyoruz. Bu dosya da Dockerfile içinde kapalı olarak duruyor ve image içine eklenmiyor. Siz kendi ihtiyacınıza uygun bir şekilde değiştirerek Dockerfile içindeki ilgili satırları aktif ederseniz bu dosyalar da image içine gidecektir.
Önemli Uyarı ! Zamanla bu Dockerfile çalışmaz duruma gelebilir. Dockerfile içinde kullandığımız paketlerin repolardaki ömrü bitebilir, güncel sürümlerde hata çıkabilir, repolar artık kullanımdan kalkabilir veya başına başka sorunlar gelebilir. Bu nedenle alacağınız hatalarla biraz uğraşıp güncelliğini devam ettirebilirsiniz. Ayrıca hem ben güncel tutmaya çalışacağım hem de siz hata aldığınızda yorum kısmından ulaşırsanız birlikte de güncelleyebiliriz.
Tüm bunlara ek olarak benim aklımda bazı geliştirmeler daha var. Zamanla geliştirmeleri buraya da eklemeye çalışacağım. Her ne kadar Dockerfile içeriğini “best practices” olarak bilinen bazı kurallara uygun şekilde geliştirsem de şimdilik image boyutu biraz büyük ve bu beni rahatsız ediyor. Mümkün olduğunca bunu da düşürmeye çalışacağım.
Faydalı olması dileğiyle..
Bir sonraki yazıda görüşmek üzere.
İlk Yorumu Siz Yapın