The integration of Laravel, Docker, and GitLab CI/CD represents a paradigm shift in how modern PHP applications are delivered from a local development environment to a production-ready state. By leveraging containerization, developers can eliminate the "it works on my machine" phenomenon, ensuring that the environment where the code is written is identical to the environment where it is tested and eventually executed. This architectural approach utilizes GitLab CI/CD as the central nervous system, automating the pipeline of building images, executing rigorous test suites, and deploying to diverse infrastructures ranging from lightweight Kubernetes clusters (K3s) on VPS providers like Hetzner to scalable cloud environments such as AWS Elastic Beanstalk.
The core of this ecosystem is the containerization of the Laravel application. By using Docker, the application and its systemic dependencies—such as PHP extensions, Apache, and Composer—are packaged into a single, portable image. When this image is integrated into a GitLab CI/CD pipeline, every code push triggers a series of automated stages. These stages ensure that only code that has passed unit tests (via Pest or PHPUnit) and quality checks (via PHP CodeSniffer) is permitted to move forward. The deployment phase then varies based on the target infrastructure: it may involve a direct SSH push to an Ubuntu server, an update to a Kubernetes manifest monitored by ArgoCD, or an API-driven deployment to AWS.
Infrastructure and Technology Stack Requirements
Depending on the target deployment strategy, the required technology stack varies. The following table outlines the specific components used across the different implementation paths discussed in these technical workflows.
| Component | Ubuntu Server Path | K3s/Kubernetes Path | AWS Elastic Beanstalk Path |
|---|---|---|---|
| OS | Ubuntu | Debian | AWS Linux/Amazon Linux |
| Container Engine | Docker / Docker Compose | K3s / Docker | Docker |
| Orchestration | Manual / SSH | Kubernetes / ArgoCD | AWS Beanstalk |
| CI/CD Tool | GitLab CI/CD | GitLab CI/CD | GitLab CI/CD |
| Registry | GitLab Container Registry | GitLab Container Registry | AWS ECR / GitLab Registry |
| Hardware/Cloud | Ubuntu VPS | Hetzner VPS (4GB RAM/2 CPU) | AWS Cloud |
| Network/DNS | Manual DNS | Cloudflare DNS + SSL | AWS Route 53 / Cloudflare |
| Visibility | Terminal / SSH | Portainer / ArgoCD Dashboard | AWS Management Console |
Containerizing the Laravel Application
The foundation of a robust CI/CD pipeline is a well-defined Dockerfile. The goal is to create an image that contains all necessary binaries and configurations to run Laravel in a production-ready state.
The standard Docker configuration for Laravel typically starts from a PHP image with Apache integrated. For instance, using php:8-apache as the base image provides a stable foundation. The build process involves several critical layers:
- System Dependencies: The installation of system-level packages such as
curl,libpng-dev,libjpeg-dev,libfreetype6-dev,libzip-dev,zip,unzip, andsupervisor. These are essential for handling image processing, file compression, and process management. - PHP Extensions: The configuration and installation of specific extensions including
gd(configured with freetype and jpeg),bcmath,pdo,pdo_mysql, andzip. These extensions allow Laravel to communicate with databases and handle complex mathematical operations and image manipulation. - Testing Tools: The installation of
pcovvia PECL. This is critical for the CI/CD pipeline to generate test coverage reports, allowing developers to see which parts of the codebase are not being exercised by the test suite. - Web Server Configuration: Enabling the Apache
rewritemodule viaa2enmod rewrite, which is mandatory for Laravel's routing system to function correctly. - Application Integration: Copying the source code from the local directory into
/var/www/htmland integrating Composer by copying the binary from the official Composer image. - Virtual Host Setup: Overwriting the default Apache configuration with a custom
000-default.confto ensure the document root points to the/publicdirectory of the Laravel application.
The resulting image exposes port 80 and uses apache2-foreground as the primary command to keep the container running and serving traffic.
GitLab CI/CD Pipeline Configuration
The .gitlab-ci.yml file acts as the blueprint for the entire automation process. This file defines the stages the code must pass through before it is considered deployable.
Build and Test Stages
In a comprehensive Laravel pipeline, the "Build" stage is not just about compiling assets but ensuring the environment is stable.
- Unit Testing: The pipeline executes tests using PHPUnit or Pest. To facilitate this, a
.env.cifile is used during the build and test stages. This ensures that the CI environment uses a specific set of credentials and configurations (such as a dedicated testing database) rather than production secrets. - Code Quality: The use of PHP CodeSniffer (PHP-CS) ensures that the code adheres to defined styling standards, preventing "dirty" code from entering the main branch.
- Image Creation: Once tests pass, the pipeline builds the Docker image. The image is tagged with a version (e.g.,
v0.0.1) and pushed to the GitLab Container Registry. This registry acts as a secure, private storage for images that the deployment server can pull from.
Deployment Strategies
The deployment stage is where the pipeline interacts with the external infrastructure. There are three primary methods utilized depending on the architecture.
Deployment to Ubuntu Servers via SSH
This method is common for smaller projects or those requiring direct control over the VPS.
- SSH Key Management: A private SSH key is generated (usually
~/.ssh/id_rsa). The public key is added to the server, while the private key is stored as a GitLab CI/CD variable namedSSH_PRIVATE_KEY. - Network Configuration: The server's IP address is stored as a masked variable named
PRODUCTION_IPto prevent the IP from being exposed in the pipeline logs. - Execution: The pipeline uses these credentials to SSH into the server and trigger a pull of the latest Docker image and a restart of the containers.
Deployment via Kubernetes and ArgoCD
For high-availability environments, a GitOps approach using K3s and ArgoCD is implemented.
- Image Tagging: The pipeline updates the image tag in the
kubernetes/apps/lci/values.yamlfile. - GitOps Workflow: A commit is made back to the repository with the updated image tag.
- Automatic Synchronization: ArgoCD monitors the repository for changes. Once it detects a new tag in the
values.yamlfile, it automatically applies the change to the K3s cluster, pulling the new image from the GitLab Registry and performing a rolling update. - Management Tools: Portainer and the ArgoCD dashboard are used for infrastructure visibility, allowing administrators to monitor pod health and container status.
Deployment to AWS Elastic Beanstalk
Deploying to AWS requires a different set of authentication and integration steps.
- IAM Configuration: An IAM user must be created in the AWS Console with an Access Key ID and Secret Access Key.
- GitLab Variable Integration: The following variables must be configured in the GitLab project settings:
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_DEFAULT_REGION
- Pipeline Logic: The
.gitlab-ci.ymlfile coordinates the upload of the application bundle to AWS. A specific feature in some configurations allows users to skip testing by adding[skip tests]to the commit message, which saves CI minutes during minor documentation updates.
Practical Implementation Steps
To implement these systems, developers must follow a sequence of configuration and command executions.
Local Setup and Image Preparation
Before the pipeline can run, the image must be successfully built and pushed to the registry.
- Authentication: Obtain the
CI_REGISTRY,CI_REGISTRY_USERNAME, andCI_REGISTRY_TOKEN(created via Profile > Edit profile > Access tokens withread_registryandwrite_registrypermissions). - Registry Login:
bash docker login registry.gitlab.com - Building the Image:
bash docker build -f ./docker/Dockerfile --target prod -t registry.gitlab.com/<username>/laravel-cicd:v0.0.1 ./ - Pushing to Registry:
bash docker push registry.gitlab.com/<username>/laravel-cicd:v0.0.1
GitLab Variable Configuration
The security of the pipeline depends on the correct use of GitLab CI/CD variables.
- For AWS deployments, users must navigate to Settings > CI/CD and add the
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY. - For Ubuntu server deployments, the
SSH_PRIVATE_KEYmust be pasted into the value field, and thePRODUCTION_IPmust be marked as "masked" and "hidden" to ensure security. - For database testing, the
MYSQL_DATABASEvariable should be set to match the testing database defined in thephpunit.xmlfile.
Detailed Analysis of the CI/CD Workflow
The transition from a manual deployment process to an automated GitLab CI/CD pipeline fundamentally changes the development lifecycle. In a traditional manual setup, a developer would SSH into a server, run git pull, run composer install, and restart the server. This is prone to human error and creates significant downtime.
The automated approach solves this by utilizing an "immutable infrastructure" pattern. When a Docker image is built, it is locked. The exact same bytes that were tested in the CI stage are the bytes that are deployed to production. This eliminates the risk of environment drift, where the production server has a different version of a PHP extension than the development machine.
The inclusion of ArgoCD in the Kubernetes path further enhances this by introducing GitOps. In GitOps, the state of the infrastructure is defined in Git. If a pod in the K3s cluster fails or is manually changed, ArgoCD detects the drift from the values.yaml file in the repository and automatically reverts the cluster to the desired state. This provides a level of self-healing that is impossible in standard VPS deployments.
Furthermore, the integration of AWS Elastic Beanstalk allows for effortless scaling. By utilizing GitLab's provided Docker images with AWS libraries, the pipeline can trigger deployments that scale the underlying EC2 instances based on traffic, while still maintaining the rigorous testing standards defined in the .gitlab-ci.yml file.
Conclusion
The implementation of a GitLab CI/CD pipeline for Laravel, supported by Docker and various deployment targets, creates a professional-grade software delivery pipeline. By moving from simple script-based deployments to containerized workflows, organizations achieve greater consistency and reliability. Whether using a low-cost Hetzner VPS with K3s and ArgoCD for cost-efficiency or AWS for global scalability, the core principle remains the same: automate everything.
The use of a structured pipeline—starting from the php:8-apache base image, moving through automated Pest/PHPUnit testing and PHP-CS quality checks, and ending with a secure deployment via SSH or GitOps—minimizes the risk of production failures. The ability to use a .env.ci file separates the concerns of testing and production, while the use of GitLab's masked variables ensures that sensitive credentials like AWS_SECRET_ACCESS_KEY or SSH_PRIVATE_KEY are never exposed. Ultimately, this setup allows developers to focus on writing features rather than managing servers, transforming the deployment process from a high-stress event into a non-event.