Laravel + Docker + Gitlab. Where to begin

I usually always did without a docker and thought that a docker is needed only for large projects in large companies. But one day I saw how a docker works in tandem with a friend’s gitlab and realized that I still should study it. However, as usually happens, I did not find one suitable article - they were either too complex or incomplete, or implied that you all know by itself. I had to look for various sources for a long time, put it all together and in the end I managed to make a simple project and CI / CD for it.

All work can be divided into three parts: on the local machine, on the hitlab and on the server.

So, for the implementation of the project, we need a gitlab account and a remote server with KVM or XEN virtualization.

Part 1. Local machine


On the local machine, you need to install docker.

Comment
. Docker Linux ( Ubuntu, ), Windows MacOS. macos , Windows . - , linux . - , . VirtualBox. Ubuntu

To install on a Linux environment, you must run the following commands.

Delete old containers:

sudo apt-get remove docker docker-engine docker.io containerd runc

Update apt:

sudo apt-get update

Install the following packages so that you can download docker from the repository via https:

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

Add official GPG docker key:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Make sure the print is correct:

sudo apt-key fingerprint 0EBFCD88

Answer:

pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

Download stable version:

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

Update apt again:

sudo apt-get update

Install the latest docker engine:

sudo apt-get install docker-ce docker-ce-cli containerd.io

Check docker operation:

sudo docker run hello-world

If everything is correct, the download of the Hello World image will begin.

Full instructions in the official documentation of the docker .

We also need to install docker-compose. The official instruction is here .

To install it, execute the commands in the terminal.

Download from repository:

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Adding an exercise right:

sudo chmod +x /usr/local/bin/docker-compose

Version Check:

sudo docker-compose --version

We installed the docker, now it is necessary to collect the image. To do this, I used the article from the digitalocean website: www.digitalocean.com/community/tutorials/how-to-set-up-laravel-nginx-and-mysql-with-docker-compose-ru . There will be a reprint of this article.

Downloading Laravel and installing dependencies

In the first step, we download the latest version of Laravel and install the project dependencies, including Composer, the application-level PHP package manager. We will install these dependencies using Docker so as not to perform a global installation of Composer.

Go to your home directory and clone the latest version of Laravel into a directory called laravel-app:

cd ~
git clone https://github.com/laravel/laravel.git laravel-app

Go to laravel-app directory:

cd ~/laravel-app

Then mount the composer image from Docker into the directories you need for your Laravel project to avoid the overhead of installing Composer globally:

docker run --rm -v $(pwd):/app composer install

The -v and --rm flags of the docker run command create a virtual container that binds to the current directory until it is deleted. The contents of your ~ / laravel-app directory will be copied to the container, and the contents of the Composer created inside the vendor folder container will be copied to the current directory.

In conclusion, set the permissions level in the project directory so that it is owned by a user without root privileges:

sudo chown -R $USER:$USER ~/laravel-app

This will be important when you write the Dockerfile for the image of your application, as it will allow you to work with the application code and start processes in the container without root privileges.

Now you have placed the application code and can proceed to the definition of services using Docker Compose.

Creating a Docker Compose File

Building applications with Docker Compose simplifies the configuration and versioning process in your infrastructure. To customize our Laravel application, we will create a docker-compose file with the definition of web server services, database and application.

Open the file:

nano ~/laravel-app/docker-compose.yml

Three services are defined in the docker-compose file: app, webserver and db. Add the following code to the file, while replacing the root password for MYSQL_ROOT_PASSWORD, defined as the db service environment variable, with a password of your choice:

~/laravel-app/docker-compose.yml

version: '3'
services:

  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    working_dir: /var/www
    networks:
      - app-network

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
      - "80:80"
      - "443:443"
    networks:
      - app-network

  #MySQL Service
  db:
    image: mysql:5.7.22
    container_name: db
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    networks:
      - app-network

#Docker Networks
networks:
  app-network:
    driver: bridge

The following services are included here:

  • app: This service definition contains the Laravel application and launches the personalized Docker image, digitalocean.com/php. It also sets the working_dir parameter in the container to / var / www.
  • webserver: this service definition takes the nginx: alpine image from Docker and opens ports 80 and 443.
  • db: this service definition retrieves the mysql: 5.7.22 image from Docker and defines new environment variables, including the laravel database for your application and the root password for the database. You can use any database name you want, you should also replace your_mysql_root_password with your own strong password. This service definition also maps host port 3306 to container port 3306.

Each container_name property defines a container name corresponding to the service name. If you do not define this property, Docker will give each container names consisting of the name of a historical person and a random word, separated by an underscore.

To simplify the interaction between containers, services connect to the connecting network called app-network. The connecting network uses a software bridge that allows containers connected to this network to communicate with each other. The bridge driver automatically sets host rules so that containers on different connecting networks cannot communicate directly with each other. This improves application security because only related services can communicate with each other. It also means that you can specify different networks and services that connect to related functions: for example, client application services can use the frontend network, and server services can use the backend network.

Now, let's see how to add volumes and bind mounted images to service definitions to permanently save application data.

Persistent data storage

Docker has powerful and convenient means for persistent data storage. In our application, we will use volumes and mounted images to permanently save database files, applications, and configurations. Volumes provide backup flexibility and preservation upon termination of the container's life cycle, and mountable mountable images make it easy to modify code during development by immediately reflecting changes to host files or directories in containers. We use both options.

Warning!
, , . , Docker . .

Define the volume named dbdata in the docker-compose file in the db service definition to persist the MySQL database:

~/laravel-app/docker-compose.yml

...
#MySQL Service
db:
  ...
    volumes:
      - dbdata:/var/lib/mysql
    networks:
      - app-network
  ...

A volume named dbdata is used to permanently save the contents of the / var / lib / mysql folder inside the container. This allows you to stop and restart the db service without losing data.
Add a dbdata volume definition at the end of the file:

~/laravel-app/docker-compose.yml

...
#Volumes
volumes:
  dbdata:
    driver: local

With this definition, you can use this volume for different services.

Then add the mount image binding to the db service for the MySQL configuration files:

~/laravel-app/docker-compose.yml

...
#MySQL Service
db:
  ...
    volumes:
      - dbdata:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/my.cnf
  ...

This mounted image binds the ~ / laravel-app / mysql / my.cnf file to the /etc/mysql/my.cnf directory in the container.

Then add the mounted images to the web server service. There will be two: one for the application code, and the other for determining the Nginx configuration

~/laravel-app/docker-compose.yml

#Nginx Service
webserver:
  ...
  volumes:
      - ./:/var/www
      - ./nginx/conf.d/:/etc/nginx/conf.d/
  networks:
      - app-network

The first mounted image binds the application code in the ~ / laravel-app directory to the / var / www directory inside the container. The configuration file, added to ~ / laravel-app / nginx / conf.d /, is also mounted in /etc/nginx/conf.d/ in the container, which allows you to add and change the contents of the configuration directory as needed.

In conclusion, add the following mounts of mounted images to the app service for application code and configuration files:

~/laravel-app/docker-compose.yml

#PHP Service
app:
  ...
  volumes:
       - ./:/var/www
       - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
  networks:
      - app-network

The app service binds the mounted image of the ~ / laravel-app folder, which contains the application code, to the / var / www folder. This will speed up the development process, since any changes in the local application directory will immediately be reflected in the container. You also attach the PHP configuration file ~ / laravel-app / php / local.ini to the /usr/local/etc/php/conf.d/local.ini file in the container. Later you will create a local PHP configuration file.

Your docker-compose file will now look like this:

~/laravel-app/docker-compose.yml

version: '3'
services:

  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    working_dir: /var/www
    volumes:
      - ./:/var/www
      - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
    networks:
      - app-network

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./:/var/www
      - ./nginx/conf.d/:/etc/nginx/conf.d/
    networks:
      - app-network

  #MySQL Service
  db:
    image: mysql:5.7.22
    container_name: db
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - dbdata:/var/lib/mysql/
      - ./mysql/my.cnf:/etc/mysql/my.cnf
    networks:
      - app-network

#Docker Networks
networks:
  app-network:
    driver: bridge
#Volumes
volumes:
  dbdata:
    driver: local

Creating a Dockerfile

Docker allows you to define the environment inside individual containers using a Dockerfile. Dockerfile allows you to create personalized images. which can be used to install the required application software and change the settings as required. You can transfer created images to the Docker Hub or any private registry.

The Dockerfile will be located in the ~ / laravel-app directory. Create a file:

nano ~/laravel-app/Dockerfile

This Dockerfile will specify the base image and the necessary commands and instructions to build the Laravel application image. Add the following code to the file:

~/laravel-app/php/Dockerfile

FROM php:7.2-fpm

# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/

# Set working directory
WORKDIR /var/www

# Install dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    mysql-client \
    libpng-dev \
    libjpeg62-turbo-dev \
    libfreetype6-dev \
    locales \
    zip \
    jpegoptim optipng pngquant gifsicle \
    vim \
    unzip \
    git \
    curl

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www

# Copy existing application directory contents
COPY . /var/www

# Copy existing application directory permissions
COPY --chown=www:www . /var/www

# Change current user to www
USER www

# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]

First, the Dockerfile creates the image on top of the php: 7.2-fpm Docker image. This is an image based on an installed instance of PHP FastCGI PHP-FPM. This file also installs the required packages for Laravel: mcrypt, pdo_mysql, mbstring and imagick with composer.

The RUN directive specifies commands for updating, installing, and configuring parameters inside a container, including a dedicated user and a group named www. The WORKDIR statement sets the directory / var / www as the working directory of the application.

Creating a separate user and group with limited access rights reduces the vulnerability when launching Docker containers, which by default run with root privileges. Instead of running this container with root privileges, we created a www user with read and write permissions for the / var / www folder using the COPY command with the --chown flag to copy the permissions of the application folder.

The EXPOSE command opens port 9000 in the container for the php-fpm server. CMD indicates the command that should be run after the container is created. Here, CMD indicates the php-fpm command that starts the server.

When you are finished making changes, save the file and close the editor.

Now you can move on to defining your PHP configuration.

PHP setup

You have defined the infrastructure in the docker-compose file, and now you can configure the PHP service to act as a PHP processor for incoming Nginx requests.

To configure PHP, you will create a local.ini file in the php folder. This is the file that you linked to the /usr/local/etc/php/conf.d/local.ini file in the container above. Creating this file will allow you to ignore the default php.ini file that PHP reads at startup.

Create a php directory:

mkdir ~/laravel-app/php

Then open the local.ini file:

nano ~/laravel-app/php/local.ini

To demonstrate PHP setup, we will add the following code to set file upload size limits:

~/laravel-app/php/local.ini

upload_max_filesize=40M
post_max_size=40M

The upload_max_filesize and post_max_size directives set the maximum allowed size of the uploaded files and show how to set php.ini configurations from the local.ini file. You can insert any PHP configuration parameter that you want to ignore in the local.ini file.

Configuring Nginx

When you configure the PHP service, you can modify the Nginx service to use PHP-FPM as a FastCGI server to serve dynamic content. The FastCGI server is based on a binary protocol for the interaction of interactive programs with a web server. Additional information can be found in the article “Understanding and Implementing FastCGI Proxies in Nginx”.
To configure Nginx, you will create an app.conf file with the services configuration in the ~ / laravel-app / nginx / conf.d / folder.

First create the nginx / conf.d / directory:

mkdir -p ~/laravel-app/nginx/conf.d

Then create the app.conf configuration file:

nano ~/laravel-app/nginx/conf.d/app.conf

Add the following code to the file to configure Nginx:

~/laravel-app/nginx/conf.d/app.conf

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}

The server block configures the Nginx web server using the following directives:

  • listen: this directive defines the port that the server listens for incoming requests.
  • error_log and access_log: these directives define files for logging.
  • root: this directive sets the path to the root folder, forming the full path for any requested file in the local file system.

In the php location block, the fastcgi_pass directive indicates that the app service is listening on a TCP socket on port 9000. With it, the PHP-FPM server listens on the network, not on the Unix socket. Although the Unix socket provides a slight speed advantage over the TCP socket, it does not have a network protocol and it skips the network stack. In cases where hosts are located on the same system, using a Unix socket may make sense, but if the services are running on different hosts, the TCP socket provides an advantage by allowing you to connect to distributed services. Since our app and webserver containers run on different hosts, it is more efficient to use a TCP socket in our configuration.

When you are finished making changes, save the file and close the editor.

Thanks to the binding created earlier, any changes in the nginx / conf.d / folder are directly reflected in the webserver container.

Now let's look at the MySQL parameters.

Setting up MySQL

After setting up PHP and Nginx, you can activate MySQL as a database for your application.

To configure MySQL, you need to create the my.cnf file in the mysql folder. This is the file that you attached to the /etc/mysql/my.cnf file inside the container during the database configuration phase. Mounting the mounted image allows you to ignore any my.cnf options, if and when required.

To demonstrate how this works, we will add settings to my.cnf that include the general query log and set the log file.

Create a mysql directory:

mkdir ~/laravel-app/mysql

Create the my.cnf file:

nano ~/laravel-app/mysql/my.cnf

Add the following code to the file to activate the query log and set the location of the log file:

~/laravel-app/mysql/my.cnf

[mysqld]
general_log = 1
general_log_file = /var/lib/mysql/general.log

The my.cnf file supports logs by setting the general_log parameter to 1, which enables general logs. The general_log_file parameter specifies where the logs will be stored.

Starting containers and changing environment settings

You defined all the services in the docker-compose file and created configuration files for these services. Now you can run containers. In conclusion, we will create a copy of the .env.example file that Laravel includes by default and name it .env, since Laravel uses such a file to determine the environment:

cp .env.example .env

After starting the containers, we will configure specific installation parameters in this file.

Now all your services are defined in the docker-compose file, and you just need to run one command to start all containers, create volumes and configure and connect networks:

docker-compose up -d

The first time you launch docker-compose up, all the necessary Docker images will be downloaded, which may take some time. After downloading the images and saving them on the local computer, Compose will create your containers. The -d flag converts the process into a daemon with which containers remain running in the background.

After the process is complete, use the following command to list all running containers:
docker ps


You will see the following results with data on the app, webserver and db containers:

Output
CONTAINER ID        NAMES               IMAGE                             STATUS              PORTS
c31b7b3251e0        db                  mysql:5.7.22                      Up 2 seconds        0.0.0.0:3306->3306/tcp
ed5a69704580        app                 digitalocean.com/php              Up 2 seconds        9000/tcp
5ce4ee31d7c0        webserver           nginx:alpine                      Up 2 seconds        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp

In these results, the CONTAINER ID is a unique identifier for each container, and NAMES lists the service names for each container. You can use both of these identifiers to access containers. IMAGE defines the image name of each container, and STATUS provides information on the status of the container: started, restarted, or stopped.

Now you can modify the .env file in the app container to add specific parameters to your system.

Open the file with docker-compose exec, which allows you to run specific commands in containers. In this case, you open the file for editing:

docker-compose exec app nano .env

Locate the block specifying DB_CONNECTION and update it to reflect your system setup. You will change the following fields:

  1. DB_HOST will be your db database container.
  2. DB_DATABASE will be the laravel database.
  3. DB_USERNAME will be the username for your database. In this case, we will use laraveluser.
  4. DB_PASSWORD will be a password protected for this user account.

/var/www/.env

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laraveluser
DB_PASSWORD=your_laravel_db_password

It is also necessary to correct the same variables in the .env.example file, since it will be used later when deploying to the server.

Then configure the application key for Laravel with the php artisan key: generate command. This command will generate a key and copy it to the .env file, which will protect user sessions and encrypted data:

docker-compose exec app php artisan key:generate

Now you have all the necessary environment settings to run the application. To cache these settings in a file that speeds up application loading, run the command:

docker-compose exec app php artisan config:cache

Configuration settings will be uploaded to the /var/www/bootstrap/cache/config.php file in the container.

Finally, open the localhost site in your browser . The main page of the Laravel application opens.

Creating a MySQL user

When installing MySQL, by default only an administrative root account is created with unlimited privileges to access the database server. Typically, when working with a database, it is best to avoid using an administrative root account. Instead, we will create a special database user for our application’s Laravel database.
To create a new user, start the bash interactive shell in the db container using the docker-compose exec command:

docker-compose exec db bash

Inside the container, log in to the MySQL root administrative account:

mysql -u root -p

You will be prompted to enter the password specified for the MySQL root account when installed in the docker-compose file.

First, check for the laravel database defined in the docker-compose file.
Run the show databases command to verify existing databases:

show databases;

In the results you should see the laravel database:

Output
+--------------------+
| Database           |
+--------------------+
| information_schema |
| laravel            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

Then create a user account that will be allowed access to this database.
We use the laraveluser username, but you can replace it with any preferred name. Just make sure the username and password match those in the .env file in the previous step:

GRANT ALL ON laravel.* TO 'laraveluser'@'%' IDENTIFIED BY 'your_laravel_db_password';

Update privileges to notify MySQL server of changes:

FLUSH PRIVILEGES;

Close MySQL:

EXIT;

Exit the container:

exit

Now you can do the migration to test the database:

docker-compose exec app php artisan migrate

The results of the migration confirmation are as follows:

Output

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table

Part 2. Gitlab


In Hitlab, you need to create a new project.

Now we need to save the project in the hitlab repository. To do this, call the following commands from the project folder on the local machine:

git init
git remote add origin git@gitlab.com:<>/<>  
git remote add origin https://gitlab.com/<>/<>      SSH
git add .
git commit -m "Initial commit"
git push -u origin master

The project should appear in Project Overview -> Details.
To make it convenient to immediately get the finished environment, we save the docker image of the environment in the hitlist register.

To do this, you must do:

docker login registry.gitlab.com

And throw the image on gitlab:

docker build -t registry.gitlab.com/<>/<> .
docker push registry.gitlab.com/<>/<>

The image will be located in Packages-> Container Registry.

To finish with gitlab, we immediately get the key to gitlab-runner. To do this, go to Setting-> CI / CD-> Runner. The key is in step 3 in the section Manual configuration (Set up a specific Runner manually).

Part 3. Server configuration


VPS server must be taken with virtualization type KVM or XEN. Virtualization like OpenVZ shares the core of the system between all users, so it does not have the ability to change kernel parameters. For the test, I took the KVM server with Docker preinstalled. However, there may not be a docker on the server. In this case, you must install it manually. The algorithm is the same as when installing on the local machine. It is also necessary to check the php version. For Laravel you need at least 7.2. I also had to install the extension for php ext-mbstring separately (in my case for php 7.3):

sudo apt-get update
sudo apt-get install php7.3-mbstring

Next, we need to install gitlab-runner. Runner is a service that will accept a webhook from a hitlab when receiving a new version and deploy everything on our server.

To install gitlab-runner you need to do:

curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64

After downloading, set permission to execute:

sudo chmod +x /usr/local/bin/gitlab-runner

Next, create the gitlab-runner user and run the gitlab runner service:

sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start

Register runner. To do this, we need the token from part 2 of this article:

sudo gitlab-runner register

In response, they will ask you for the address of your hitlab.

Specify gitlab.com :

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
https://gitlab.com

Next, you need to enter the token. Enter the token from part 2.

Please enter the gitlab-ci token for this runner
xxx

Next, specify a description and tags separated by commas. Then we are offered to choose an executor. Here you need to select a shell:


Please enter the executor:
shell

As I understand it, the executor is an environment in which the code from the .gitlab-ci.yml file is executed. There are bash, ssh, docker, parallels, virtualbox and kubernets to choose from. The documentation recommends that if you do not know what to use, use bash. This is a universal option that runs on the command line on your server.

Then we need to add the gitlab-runner user to the docker user group.

sudo usermod -aG docker gitlab-runner

To avoid access errors, add to sudoers

sudo nano /etc/sudoers

line

gitlab-runner ALL=(ALL) NOPASSWD: ALL

Now we can create the .gitlab-ci.yml file. It is necessary for the execution of the so-called Pipeline: a sequence of commands for deploying a project.

To do this, go to the project repository on the hitlist and click Create a new file. Gitlab itself will offer file templates, among them you must select .gitlab-ci.yml. After creating a file in gitlab, you can select a template for the contents of the file. I chose laravel and redid it a bit for myself:


# This file is a template, and might need editing before it works on your project.
# Official framework image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/php
# .    ,        
image: registry.gitlab.com/<>/<>:latest

# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
services:
  - mysql:latest
#    
variables:
  MYSQL_DATABASE: laravel
  MYSQL_ROOT_PASSWORD: ***********

# This folder is cached between builds
# ,      
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
cache:
  paths:
    - vendor/
    - node_modules/

# This is a basic example for a gem or script which doesn't use
# services such as redis or postgres
#     
before_script:
  #   
  - sudo apt-get update -yqq
  #    nodejs
  - sudo apt-get install gnupg -yqq
  #  Node   12
  - curl -sL https://deb.nodesource.com/setup_12.x | sudo bash -
  #  
  - sudo apt-get install git nodejs libcurl4-gnutls-dev libicu-dev libmcrypt-dev libvpx-dev libjpeg-dev libpng-dev libxpm-dev zlib1g-dev libfreetype6-dev libxml2-dev libexpat1-dev libbz2-dev libgmp3-dev libldap2-dev unixodbc-dev libpq-dev libsqlite3-dev libaspell-dev libsnmp-dev libpcre3-dev libtidy-dev -yqq
  #  composer
  - curl -sS https://getcomposer.org/installer | php
  - php composer.phar install
  - composer install
  #   Node
  - npm install
  # Copy over testing configuration.
  # Don't forget to set the database config in .env.testing correctly
  - DB_HOST=mysql
  - DB_DATABASE=laravel
  - DB_USERNAME=root
  - DB_PASSWORD=*********
  #  .env.example    .env
  - cp .env.example .env
  #  npm build
  - npm run dev
  #       laravel
  - php artisan key:generate
  - php artisan config:cache
  - php artisan route:clear
  - php artisan config:clear
  - php artisan cache:clear
  #  .
  - docker-compose exec app php artisan migrate
  #   
  #- docker-compose exec app php artisan db:seed

#
test:
  script:
    #  
    - php vendor/bin/phpunit --coverage-text --colors=never
    #  npm
    - npm test

#       
deploying:
  stage: deploy
  script:
    - echo "Deployed"
    - docker-compose stop
    - docker-compose up -d

After successfully executing the pipeline (CI / CD-> Pipelines) at the ip address of your server, you should see your laravel page.

To configure CI / CD, I used instructions from Sean Bradley:


and medium.com/@sean_bradley/auto-devops-with-gitlab-ci-and-docker-compose-f931233f080f

All Articles