Introduction
In this post, a DevOps environment is created using Compose. The following picture shows the participating components in this post:
-
Git Server - At its core, a git server is required for developers to push/merge their code. Then, the git server can call a CI/CD server/agent to execute a
pipelinebased on the defined event/hook. For git server, in this postGitLab CEis used. -
CI/CD Server - Jenkins is one of the most famous CI/CD applications. However,
GitLab Runneris more convenient as it is the integrated and default CI/CD tools for GitLab server. -
Artifact/Image Repository - After source code build, the output artifact must be shipped to the server. Since Docker is used to run applications on servers, the final package must be deployed as Docker image. So a registry is required in this case to mediate images between servers.
Sonatype Nexus 3is a professional repository management tool, and it supports various development/build tools such as maven, npm, and so on. -
Deployment Servers/Cluster - At the end of a CD pipeline, a server or cluster is required for executing the container(s). The CD can be translated into following paradigms:
Continuous Delivery- it targets a pre-production environment, called development/test, to evaluate the release by QA users or customers.Continuous Deployment- after QA/customer validation and verification cycles, in another pipeline, the final release can be deployed in production.

Installation
The DevOps environment is installed via Docker Compose. So it is the prerequisite, and you can learn about it in Docker to the Point - Part 2.
It is also highly recommended to setup all the containers on the Linux box without any graphical desktop and NetworkManager must be disabled.
You can use a virtual machine software.
Note
During evaluation of this example, some unexpected network issues are encountered. After some search, due to this [Ref], Docker strongly recommends that
NetworkManagermust be disabled.
Now, create the directory DevOps containing the following files:
.env- a key-value file for defined variables in other filesinit.sh- an initialization scriptdocker-compose.yml- main Compose fileregister-runner.sh- a script to registergitlab-runnercontainer in GitLab server
Then, follow the below steps (commands should be executed in DevOps directory):
chmod +x init.sh && sudo ./init.shdocker-compose up -d- Config GitLab Server
- Register GitLab Runner
- Config Nexus
.env
Note: So based on the above .env, for the rest of this document ${GITLAB_DOMAIN} means gitlab.devops.local
and ${NEXUS_DOMAIN} means nexus.devops.local.
Note: The above format (double-quoted values) are supported in newer version of docker-compose.
For this tutorial, version 1.27.4 is used.
init.sh
docker-compose.yml
register-runner.sh
Applications
Now execute docker-compose ps and you must see all containers state Up (GitLab may take some time to become healthy).
The following sections describe each application.
Traefik
The Traefik reverse proxy is setup due to previous article Docker to the Point - Part 2:
http://HOST:8080- Traefik dashboard with basic authadmin:admin


GitLab
The GitLab server is accessible via http://${GITLAB_DOMAIN}. At first, it asks you the password for user root.
Then you can login via user root and the entered password:
- GitLab references for Docker (GitLab Docker)
- In
docker-compose.ymllines 10-13, a default config is passed to container viaGITLAB_OMNIBUS_CONFIG:gitlab_rails['registry_enabled'] = falseandregistry['enable'] = false- default GitLab registry for Docker is disabledgitlab_rails['backup_keep_time'] = 604800- for backup, 7-days retention window is set
- If you want to disable Auto DevOps - Goto
Admin Area > Settings > CI/CD - Create a group for all of your projects and set CI/CD variables in that group
- The runner container must be added to GitLab server, and you need the token in
registry-runner.shscript.- Its token is in
Admin Area > Overview > Runnersin the following picture:
- Its token is in

GitLab Runner
The GitLab Runner is the agent for CI/CD of GitLab server. You can register multiple runners for a single GitLab server, and in this way the CI/CD processes can be spread over multiple nodes and CI/CD becomes scalable.
- GitLab Runner reference for registration via Docker (Registering Runners)
- In the previous image copy the token and execute
./register-runner.sh TOKEN. Thegitlab-runnercontainer is registered as a runner as depicted in the following picture:

Sonatype Nexus 3
Sonatype Nexus is one of the greatest open source repository management software. It supports various repository types such as Docker registry, Maven, NPM, and so on. This post only presents its Docker registry feature.
Note: In spite of Docker registry feature in GitLab, Nexus 3 is still the favorite repository management application for supporting other types of repository such as maven, npm, and so on. If you only need a Docker registry, then GitLab may be more convenient.
http://NEXUS_DOMAIN- First page of Nexus- Login with user
adminand the password is in${VOL_BASE_DIR}/nexus/admin.passwordtemp file. - Create a blob store called
docker_hub - Create a proxy Docker repository for
hub.docker.comwithout setting any HTTP port, and set blobdocker_hub - Create a blob store called
docker_private - Create a hosted Docker repository on HTTP port
8083, and set blobdocker_private - Create a group Docker repository on HTTP port
8082and add previous ones to this - Enable
Docker Bearer Token Realm - To push an image to the hosted repo
docker login -u USER -p PASS ${NEXUS_DOMAIN}:8083docker push ${NEXUS_DOMAIN}:8083/NAME:VER
- To pull image from the group repo using proxy (original from
hub.docker.com)docker pull ${NEXUS_DOMAIN}/IMAGE_ADDRESS_ON_HUBdocker pull nginx:1.18 -> docker pull ${NEXUS_DOMAIN}/nginx:1.18docker pull confluentinc/cp-kafka:5.3.1-1 -> docker pull ${NEXUS_DOMAIN}/confluentinc/cp-kafka:5.3.1-1
- To pull from the group repo
docker pull ${NEXUS_DOMAIN}/NAME:VER- Default port is enabled in Traefik for Nexus with
/v2/router (docker-compose.ymllines 43-51)
Note: The ${NEXUS_DOMAIN} (for pulling) and ${NEXUS_DOMAIN}:8083(for pushing) must be added
as insecure-registries in /etc/docker/daemon.json config file.
Setup Finalization
- To backup your Gitlab, create a symlink in
/etc/cron.dailyto the following script:
- Nexus uses OrientDB for its internal usage and config storage. So it is important to back up its config data.
For this matter, it has a built-in task. You must create one. However, this task just creates files without any retention.
The following script tries to keep some latest files and remove older ones.
So create a symlink in
/etc/cron.dailyto the following script:
Using various types of repos
In this section, using nexus repos for some platforms and languages are described.
Replace NEXUS_DOMAIN with your configuration in next sections.
Maven
- In Nexus, by default, a
maven-publicrepo is created as a group repository for Maven. - Create/Edit
$HOME/.m2/settings.xmlbased on following XML content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
<mirrors>
<mirror>
<id>central</id>
<name>central</name>
<url>http://NEXUS_DOMAIN/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
</settings>
Go
- Create
go-grouprepo as a group repo for Go - Just define the environment variable
GOPROXY="http://NEXUS_DOMAIN/repository/go-group"
Docker
- Edit
/etc/docker/daemon.json, and add or updateinsecure-registrieslike the following line1 2 3
{ "insecure-registries" : ["NEXUS_DOMAIN"] }
sudo systemctl restart docker
NPM
- Create
npm-grouprepo as a group repo for NPM - Create or update
.npmrcfile in$HOMEor project root directory with lineregistry=http://NEXUS_DOMAIN/repository/npm-group/