4. Gitlab Docker container registry. CI script for docker images

Video version
(Leave your feedback on YouTube)

Continuation of the previous article. The PHP container is always modified, we have to add extensions for the framework, dependencies, and so on. Therefore, the Dockerfile with the php service always exists.

Building the php container every time on the server and on the developers' machines is not the best idea.

Firstly, and most importantly, deployment and test runs on the server can occur many times a day, building the container each time, downloading and installing the same dependencies is irrational and time-consuming.

Secondly, consistency - in production, staging, and testing, the development environment will always be the same, without adjustments for versions of any dependencies.

For Gitlab, I create a new project in the infrastructure subgroup named swoole.

.gitlab-ci.yml
  stages:
    - build

  default:
    image: docker:26.1.3-alpine3.19
    services:
      - docker:26.1.3-dind
    before_script:
      - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY

  variables:
    IMAGE_NAME: 'swoole/core'
    IMAGE_NAME_DEV: $CI_REGISTRY_IMAGE/dev:${CI_COMMIT_TAG}
    IMAGE_NAME_PROD: $CI_REGISTRY_IMAGE/prod:${CI_COMMIT_TAG}

  build-image:
    stage: build
    script:
      - docker build -t $IMAGE_NAME -f Dockerfile .
      - docker build -t $IMAGE_NAME_DEV -f dev.Dockerfile . --build-arg SOURCE=$IMAGE_NAME
      - docker build -t $IMAGE_NAME_PROD -f prod.Dockerfile . --build-arg SOURCE=$IMAGE_NAME
      - docker push $IMAGE_NAME_DEV
      - docker push $IMAGE_NAME_PROD
    rules:
      - if: '$CI_COMMIT_TAG =~ /^v(\d+\.)?(\d+\.)?(\*|\d+)$/'

Here, note:

  • $CI_COMMIT_TAG - tag name. Any release is done with tags.
  • docker login - command to log in to the Docker registry.
  • $CI_REGISTRY_USER, $CI_REGISTRY_PASSWORD, $CI_REGISTRY - predefined gitlab variables
  • docker build -t $IMAGE_NAME -f Dockerfile . - build the core image. From it, build the prod, dev, and any other versions.
  • if: '$CI_COMMIT_TAG =~ /^v(\d+\.)?(\d+\.)?(\*|\d+)$/' - condition under which the build step runs. In this case, it runs only for tags named with the letter v and normal semantic versioning.
dev.Dockerfile
ARG SOURCE

FROM ${SOURCE}

RUN apk add --no-cache nodejs npm git

ARG SOURCE FROM ${SOURCE} - a variable passed with the --build-arg SOURCE= command, in our case, the swoole/core image.

Project workflow:

  • All global changes are added to the Dockerfile. Usually, this includes php.ini files, all php extensions etc.
  • The dev.Dockerfile currently adds node, npm, and git. If needed, xdebug, XhProf, etc., we can install there. It's important not to enable them for production. They load the server a lot. I wouldn't enable them for dev version, better to move them to a separate container.
  • To prod.Dockerfile write all production settings, opcache, turn off display of errors, etc.

And of course, all this is described in the README.md

README.md
### Local work
0) Build core image
```sh
docker build -t local/swoole-core .
```
1) Build dev image
```sh
docker build -t local/swoole-dev -f dev.Dockerfile . --build-arg SOURCE='local/swoole-core'
```
2) Build prod image
```sh
docker build -t local/swoole-prod -f prod.Dockerfile . --build-arg SOURCE='local/swoole-core'
```
3) Use `local/swoole-prod` or `local/swoole-dev` in your projects


### Deploy

0) Commit your changes
1) Merge to main
2) Switch to main branch
3) Make tag with {version} (using semantic rules https://semver.org/) 
should increment [last tags](https://gitlab.com/some_project_name/back/infrastructure/swoole/container_registry) and match the expression
```regexp
/^v(\d+\.)?(\d+\.)?(\*|\d+)$/
```
3) Push your tag
```
git push origin {version}
```
It will create 2 tagged versions:
- `registry.gitlab.com/some_project_name/back/infrastructure/swoole/dev:{version}` - for development
- `registry.gitlab.com/some_project_name/back/infrastructure/swoole/prod:{version}` - for production

Don't forget about .dockerignore

.dockerignore
**.git
.idea
README.md
.gitlab-ci.yml
dev.Dockerfile
Dockerfile
prod.Dockerfile