-
-
Save chris-cmsoft/d398cb87907db6f39341df53345d6925 to your computer and use it in GitHub Desktop.
| /vendor | |
| /node_modules |
| version: '3' | |
| services: | |
| # We need to run the FPM container for our application | |
| laravel.fpm: | |
| build: | |
| context: . | |
| target: fpm_server | |
| image: laravel-in-kubernetes/fpm_server | |
| # We can override any env values here. | |
| # By default the .env in the project root will be loaded as the environment for all containers | |
| environment: | |
| APP_DEBUG: "true" | |
| # Mount the codebase, so any code changes we make will be propagated to the running application | |
| volumes: | |
| # Here we mount in our codebase so any changes are immediately reflected into the container | |
| - '.:/opt/apps/laravel-in-kubernetes' | |
| networks: | |
| - laravel-in-kubernetes | |
| # Run the web server container for static content, and proxying to our FPM container | |
| laravel.web: | |
| build: | |
| context: . | |
| target: web_server | |
| image: laravel-in-kubernetes/web_server | |
| # Expose our application port (80) through a port on our local machine (8080) | |
| ports: | |
| - '8080:80' | |
| environment: | |
| # We need to pass in the new FPM hst as the name of the fpm container on port 9000 | |
| FPM_HOST: "laravel.fpm:9000" | |
| # Mount the public directory into the container so we can serve any static files directly when they change | |
| volumes: | |
| # Here we mount in our codebase so any changes are immediately reflected into the container | |
| - './public:/opt/apps/laravel-in-kubernetes/public' | |
| networks: | |
| - laravel-in-kubernetes | |
| # Run the Laravel Scheduler | |
| laravel.cron: | |
| build: | |
| context: . | |
| target: cron | |
| image: laravel-in-kubernetes/cron | |
| # Here we mount in our codebase so any changes are immediately reflected into the container | |
| volumes: | |
| # Here we mount in our codebase so any changes are immediately reflected into the container | |
| - '.:/opt/apps/laravel-in-kubernetes' | |
| networks: | |
| - laravel-in-kubernetes | |
| # Run the frontend, and file watcher in a container, so any changes are immediately compiled and servable | |
| laravel.frontend: | |
| build: | |
| context: . | |
| target: frontend | |
| # Override the default CMD, so we can watch changes to frontend files, and re-transpile them. | |
| command: ["npm", "run", "watch"] | |
| image: laravel-in-kubernetes/frontend | |
| volumes: | |
| # Here we mount in our codebase so any changes are immediately reflected into the container | |
| - '.:/opt/apps/laravel-in-kubernetes' | |
| # Add node_modeules as singular volume. | |
| # This prevents our local node_modules from being propagated into the container, | |
| # So the node_modules can be compiled for each of the different architectures (Local, Image) | |
| - '/opt/app/node_modules/' | |
| networks: | |
| - laravel-in-kubernetes | |
| mysql: | |
| image: 'mysql:8.0' | |
| ports: | |
| - '${FORWARD_DB_PORT:-3306}:3306' | |
| environment: | |
| MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' | |
| MYSQL_DATABASE: '${DB_DATABASE}' | |
| MYSQL_USER: '${DB_USERNAME}' | |
| MYSQL_PASSWORD: '${DB_PASSWORD}' | |
| MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' | |
| volumes: | |
| - 'laravel-in-kubernetes-mysql:/var/lib/mysql' | |
| networks: | |
| - laravel-in-kubernetes | |
| healthcheck: | |
| test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"] | |
| retries: 3 | |
| timeout: 5s | |
| networks: | |
| laravel-in-kubernetes: | |
| volumes: | |
| laravel-in-kubernetes-mysql: |
| # Create args for PHP extensions and PECL packages we need to install. | |
| # This makes it easier if we want to install packages, | |
| # as we have to install them in multiple places. | |
| # This helps keep ou Dockerfiles DRY -> https://bit.ly/dry-code | |
| # You can see a list of required extensions for Laravel here: https://laravel.com/docs/8.x/deployment#server-requirements | |
| ARG PHP_EXTS="bcmath ctype fileinfo mbstring pdo pdo_mysql tokenizer dom pcntl" | |
| ARG PHP_PECL_EXTS="redis" | |
| # We need to build the Composer base to reuse packages we've installed | |
| FROM composer:2.1 as composer_base | |
| # We need to declare that we want to use the args in this build step | |
| ARG PHP_EXTS | |
| ARG PHP_PECL_EXTS | |
| # First, create the application directory, and some auxilary directories for scripts and such | |
| RUN mkdir -p /opt/apps/laravel-in-kubernetes /opt/apps/laravel-in-kubernetes/bin | |
| # Next, set our working directory | |
| WORKDIR /opt/apps/laravel-in-kubernetes | |
| # We need to create a composer group and user, and create a home directory for it, so we keep the rest of our image safe, | |
| # And not accidentally run malicious scripts | |
| RUN addgroup -S composer \ | |
| && adduser -S composer -G composer \ | |
| && chown -R composer /opt/apps/laravel-in-kubernetes \ | |
| && apk add --virtual build-dependencies --no-cache ${PHPIZE_DEPS} openssl ca-certificates libxml2-dev oniguruma-dev \ | |
| && docker-php-ext-install -j$(nproc) ${PHP_EXTS} \ | |
| && pecl install ${PHP_PECL_EXTS} \ | |
| && docker-php-ext-enable ${PHP_PECL_EXTS} \ | |
| && apk del build-dependencies | |
| # Next we want to switch over to the composer user before running installs. | |
| # This is very important, so any extra scripts that composer wants to run, | |
| # don't have access to the root filesystem. | |
| # This especially important when installing packages from unverified sources. | |
| USER composer | |
| # Copy in our dependency files. | |
| # We want to leave the rest of the code base out for now, | |
| # so Docker can build a cache of this layer, | |
| # and only rebuild when the dependencies of our application changes. | |
| COPY --chown=composer composer.json composer.lock ./ | |
| # Install all the dependencies without running any installation scripts. | |
| # We skip scripts as the code base hasn't been copied in yet and script will likely fail, | |
| # as `php artisan` available yet. | |
| # This also helps us to cache previous runs and layers. | |
| # As long as comoser.json and composer.lock doesn't change the install will be cached. | |
| RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist | |
| # Copy in our actual source code so we can run the installation scripts we need | |
| # At this point all the PHP packages have been installed, | |
| # and all that is left to do, is to run any installation scripts which depends on the code base | |
| COPY --chown=composer . . | |
| # Now that the code base and packages are all available, | |
| # we can run the install again, and let it run any install scripts. | |
| RUN composer install --no-dev --prefer-dist | |
| # For the frontend, we want to get all the Laravel files, | |
| # and run a production compile | |
| FROM node:14 as frontend | |
| # We need to copy in the Laravel files to make everything is available to our frontend compilation | |
| COPY --from=composer_base /opt/apps/laravel-in-kubernetes /opt/apps/laravel-in-kubernetes | |
| WORKDIR /opt/apps/laravel-in-kubernetes | |
| # We want to install all the NPM packages, | |
| # and compile the MIX bundle for production | |
| RUN npm install && \ | |
| npm run prod | |
| # For running things like migrations, and queue jobs, | |
| # we need a CLI container. | |
| # It contains all the Composer packages, | |
| # and just the basic CLI "stuff" in order for us to run commands, | |
| # be that queues, migrations, tinker etc. | |
| FROM php:8.0-alpine as cli | |
| # We need to declare that we want to use the args in this build step | |
| ARG PHP_EXTS | |
| ARG PHP_PECL_EXTS | |
| WORKDIR /opt/apps/laravel-in-kubernetes | |
| # We need to install some requirements into our image, | |
| # used to compile our PHP extensions, as well as install all the extensions themselves. | |
| # You can see a list of required extensions for Laravel here: https://laravel.com/docs/8.x/deployment#server-requirements | |
| RUN apk add --virtual build-dependencies --no-cache ${PHPIZE_DEPS} openssl ca-certificates libxml2-dev oniguruma-dev && \ | |
| docker-php-ext-install -j$(nproc) ${PHP_EXTS} && \ | |
| pecl install ${PHP_PECL_EXTS} && \ | |
| docker-php-ext-enable ${PHP_PECL_EXTS} && \ | |
| apk del build-dependencies | |
| # Next we have to copy in our code base from our initial build which we installed in the previous stage | |
| COPY --from=composer_base /opt/apps/laravel-in-kubernetes /opt/apps/laravel-in-kubernetes | |
| COPY --from=frontend /opt/apps/laravel-in-kubernetes/public /opt/apps/laravel-in-kubernetes/public | |
| # We need a stage which contains FPM to actually run and process requests to our PHP application. | |
| FROM php:8.0-fpm-alpine as fpm_server | |
| # We need to declare that we want to use the args in this build step | |
| ARG PHP_EXTS | |
| ARG PHP_PECL_EXTS | |
| WORKDIR /opt/apps/laravel-in-kubernetes | |
| RUN apk add --virtual build-dependencies --no-cache ${PHPIZE_DEPS} openssl ca-certificates libxml2-dev oniguruma-dev && \ | |
| docker-php-ext-install -j$(nproc) ${PHP_EXTS} && \ | |
| pecl install ${PHP_PECL_EXTS} && \ | |
| docker-php-ext-enable ${PHP_PECL_EXTS} && \ | |
| apk del build-dependencies | |
| # We have to copy in our code base from our initial build which we installed in the previous stage | |
| COPY --from=composer_base --chown=www-data /opt/apps/laravel-in-kubernetes /opt/apps/laravel-in-kubernetes | |
| COPY --from=frontend --chown=www-data /opt/apps/laravel-in-kubernetes/public /opt/apps/laravel-in-kubernetes/public | |
| # We want to cache the event, routes, and views so we don't try to write them when we are in Kubernetes. | |
| # Docker builds should be as immutable as possible, and this removes a lot of the writing of the live application. | |
| RUN php artisan event:cache && \ | |
| php artisan route:cache && \ | |
| php artisan view:cache | |
| # As FPM uses the www-data user when running our application, | |
| # we need to make sure that we also use that user when starting up, | |
| # so our user "owns" the application when running | |
| USER www-data | |
| # We need an nginx container which can pass requests to our FPM container, | |
| # as well as serve any static content. | |
| FROM nginx:1.20-alpine as web_server | |
| WORKDIR /opt/apps/laravel-in-kubernetes | |
| # We need to add our NGINX template to the container for startup, | |
| # and configuration. | |
| COPY nginx.conf.template /etc/nginx/templates/default.conf.template | |
| # Copy in ONLY the public directory of our project. | |
| # This is where all the static assets will live, which nginx will serve for us. | |
| COPY --from=frontend /opt/apps/laravel-in-kubernetes/public /opt/apps/laravel-in-kubernetes/public | |
| # We need a CRON container to the Laravel Scheduler. | |
| # We'll start with the CLI container as our base, | |
| # as we only need to override the CMD which the container starts with to point at cron | |
| FROM cli as cron | |
| WORKDIR /opt/apps/laravel-in-kubernetes | |
| # We want to create a laravel.cron file with Laravel cron settings, which we can import into crontab, | |
| # and run crond as the primary command in the forground | |
| RUN touch laravel.cron && \ | |
| echo "* * * * * cd /opt/apps/laravel-in-kubernetes && php artisan schedule:run" >> laravel.cron && \ | |
| crontab laravel.cron | |
| CMD ["crond", "-l", "2", "-f"] | |
| FROM cli |
| server { | |
| listen 80 default_server; | |
| listen [::]:80 default_server; | |
| # We need to set the root for our sevrer, | |
| # so any static file requests gets loaded from the correct path | |
| root /opt/apps/laravel-in-kubernetes/public; | |
| index index.php index.html index.htm index.nginx-debian.html; | |
| # _ makes sure that nginx does not try to map requests to a specific hostname | |
| # This allows us to specify the urls to our application as infrastructure changes, | |
| # without needing to change the application | |
| server_name _; | |
| # At the root location, | |
| # we first check if there are any static files at the location, and serve those, | |
| # If not, we check whether there is an indexable folder which can be served, | |
| # Otherwise we forward the request to the PHP server | |
| location / { | |
| # Using try_files here is quite important as a security concideration | |
| # to prevent injecting PHP code as static assets, | |
| # and then executing them via a URL. | |
| # See https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#passing-uncontrolled-requests-to-php | |
| try_files $uri $uri/ /index.php?$query_string; | |
| } | |
| # Some static assets are loaded on every page load, | |
| # and logging these turns into a lot of useless logs. | |
| # If you would prefer to see these requests for catching 404's etc. | |
| # Feel free to remove them | |
| location = /favicon.ico { access_log off; log_not_found off; } | |
| location = /robots.txt { access_log off; log_not_found off; } | |
| # When a 404 is returned, we want to display our applications 404 page, | |
| # so we redirect it to index.php to load the correct page | |
| error_page 404 /index.php; | |
| # Whenever we receive a PHP url, or our root location block gets to serving through fpm, | |
| # we want to pass the request to FPM for processing | |
| location ~ \.php$ { | |
| #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini | |
| include fastcgi_params; | |
| fastcgi_intercept_errors on; | |
| fastcgi_pass ${FPM_HOST}; | |
| fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; | |
| } | |
| location ~ /\.ht { | |
| deny all; | |
| } | |
| location ~ /\.(?!well-known).* { | |
| deny all; | |
| } | |
| } |
Hi, this line according to your blog must be changed to:
COPY docker/nginx.conf.template /etc/nginx/templates/default.conf.template
Hello!
Great tutorial first of all. It's really helping me solve a client's migration to Kubernetes.
I found that on the Dockerfile the PHP version is outdated and I was getting errors on the build. Can you change it from php:8.0-fpm-alpine to php:8.1-fpm-alpine. I also changed the php:8.0-alpine in the cli step locally to keep it the same version, although it wasn't returning any errors on that part.
Also, on the web_server step, on the blog page, you indicate that the nginx template file should be created in a new folder named docker. But in the Dockerfile you attempt to copy from the root. So please change COPY nginx.conf.template /etc/nginx/templates/default.conf.template to COPY docker/nginx.conf.template /etc/nginx/templates/default.conf.template.
Cheers!
All fixed. Thanks for letting me know Peter ! Glad you're enjoying it :)