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
.
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 variablesdocker 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 letterv
and normal semantic versioning.
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
### 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
**.git
.idea
README.md
.gitlab-ci.yml
dev.Dockerfile
Dockerfile
prod.Dockerfile