When starting a new project from scratch it is convenient to have an environment where future project will be deployed at. I don’t pretend on giving the standard solution for desired purposes, but approaches described in this article seemed very useful to me.
Actually, this article is about how to setup all the tools helping for developing modern web applications.
Organizing Self hosted Java Cloud
Building the solution described in this article I was aimed to achieve the requirements:
- Each application used must run in separated Docker container for security reasons and for having straightforward deployment flow
- There must be a dashboard in order to observe the applications developed and (optionally) manage them
- There must be one point to observe all application logs
Note that approaches described below will be helpful not only for Java based solutions.
The tooling stack I selected for achieving the goals is:
- Gitea as a git server with GUI
- Jenkins as a CI/CD manager / controller
- Docker as a container manager
- Docker-compose as a container building tool
- Spring, Spring Cloud: Eureka
- SpringBoot Admin Panel
In a justification of tooling stack selected in this article I can say following:
- Gitea is a lightweight, simple solution providing a developer with all options needed to manage the development in small or medium teams
- Jenkins has very low level of entrance and has powerful script-based engine to perform CI/CD steps
- Docker is a standard of contenerization industry
- Docker-compose helps to simplify building containers
- No Kubernetes because of it requires the team to have the DevOps position or to spent much time on the very beginning of the development
- Spring is a powerful web engine written in Java
- Spring Cloud Eureka is a Service Registry where all applications to be registered in order to give the possibility to the dashboard to observe them
- SpringBoot Admin Panel is a lightweight dashboard panel. It can show metrics, logs and managing applications using JMX
Docker
Nowadays, if you want to get a high appreciated job position you need to be familiar with Docker.
Docker brings you an opportunity to manage applications easier than having them installed on clear Linux machine. I haven’t said “or on Windows” because of Windows is not my preferred OS and Java applications are preferably be deployed on Linux servers.
So, if you have Ubuntu installed (Ubuntu is mostly used on VPS), just follow the official documentations:
Prepare Ubuntu’s repositories
1. Update the apt package index and install packages to allow apt to use a repository over HTTPS
$ sudo apt-get update
$ sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
Code language: Bash (bash)
2. Add Docker’s official GPG key
$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
Code language: Bash (bash)
3. Use the following command to set up the repository
$ echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Code language: Bash (bash)
4. Update the apt
package index
$ sudo apt-get update
Code language: Bash (bash)
Install Docker
1. Installation
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Code language: Bash (bash)
2. Verify installed version
$ sudo docker run hello-world
Code language: Bash (bash)
Add your user into linux group named ‘docker’
$ sudo usermod -a -G docker <USER_NAME>
Code language: Bash (bash)
I’d advice you to have Docker-Compose be installed as well. I will use Dockerfile
and docker-compose.yaml
both further.
Install docker-compose
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
Code language: JavaScript (javascript)
Git
To me, having own stage environment is having self hosted git server. There are only few options to achieve this:
I will not provide you with all the steps to get them installed, please refer to official documentation.
I just want to say that my option of choice is Gitiea.
Preliminary settings for docker images to be communicating
You must decide how your components will run. Will you have only one server for running all components or will you have Gitea running separately from Java applications. My setup is showing how to run all applications on a single Linux machine in a single Docker host server.
Networks
Gitea will run in a network named gitea
, and components will run in separated network.
$ docker network create gitea
$ docker network create jenkins
$ docker network create <your-solution-name>
Code language: Bash (bash)
Gitea in Docker
In order to run Gitea in Docker you need to setup the database image and the very Gitea image.
Here is docker-compose.yaml
for instantiating Gitea in Docker.
version: "3.7"
networks:
gitea:
external: true
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
restart: always
networks:
- gitea
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
# - "8080:3000"
- "2221:22"
expose:
- 3000
depends_on:
- db
db:
image: postgres:13
restart: always
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea
- POSTGRES_DB=gitea
networks:
- gitea
volumes:
- ./postgres:/var/lib/postgresql/data
Code language: PHP (php)
Jenkins
Why Jenkins? Jenkins gives you a button to run tests, a button to build and deploy every single application and even will perform testing your code right after you pushing it to git
as well.
Here is the official documentations of how to install Jenkins in Docker.
I provide you with my solution of how to use Jenkins in Docker.

The picture above depicts a scheme of how Jenkins may run in Docker:
- Jenkins Controller runs in Docker container itself to be isolated and packed in bundle
- Jenkins Agents run in Docker in separated containers
- They all runs in a single Docker network
- Jenkins runs application testing on Jenkins agents
- Jenkins deploys applications services on Host machine because of they must be started into Docker containers as well
- Due to 5. Host machine is connected to Jenkins Controller as SSH Jenkins agent
- Every new deployment stage must be connected to Jenkins Controller as SSH Jenkins agent

Actually, you can run another instance of Jenkins on each another Linux Machine as an environment stage.
Generating SSH keys for Jenkins
Here is a script helping to generate SSH key pair. It will be used every time when such pair is needed.
$ cat generate-key.sh
#/bin/bash
ssh-keygen -m PEM -t rsa -b 4096 -f $(pwd)/$1.rsa
Code language: Bash (bash)
Installing Jenkins in Docker
I’d prefer to build Jenkins Controller and Agents with Dockerfiles.
I have following structure on my disk:
-build
-build/agent
-build/agent/Dockerfile
-build/controller
-build/controller/Dockerfile
-jenkins_home
-docker-compose.yaml
-rebuild.sh
Jenkins Agent Dockerfile
is:
FROM jenkins/ssh-agent:latest-jdk17
ARG DOCKER_COMPOSE_VERSION=2.15.0
USER root
RUN apt-get update && \
apt-get upgrade -y && \
apt-get -y install apt-transport-https \
ca-certificates \
curl \
gnupg2 \
git \
software-properties-common && \
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey && \
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(lsb_release -cs) \
stable" && \
apt-get update && \
apt-get -y install docker-ce && \
apt-get clean autoclean && apt-get autoremove && rm -rf /var/lib/{apt,dpkg,cache,log}/
RUN curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose
#RUN usermod -aG docker jenkins && gpasswd -a jenkins docker
USER jenkins
ENTRYPOINT ["setup-sshd"]
Code language: PHP (php)
Jenkins Controller Dockerfile
:
FROM jenkins/jenkins:lts
ARG DOCKER_COMPOSE_VERSION=2.15.0
USER root
# Install the latest Docker CE binaries and add user `jenkins` to the docker group
RUN apt-get update
RUN apt-get -y --no-install-recommends install apt-transport-https \
apt-utils ca-certificates curl gnupg2 software-properties-common && \
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey && \
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(lsb_release -cs) \
stable"
RUN apt-get update && apt-get install -y docker-ce-cli docker-ce && \
apt-get clean && \
usermod -aG docker jenkins
RUN curl -L "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose && \
chmod u+x /usr/local/bin/docker-compose
USER jenkins
RUN jenkins-plugin-cli --plugins "docker-workflow:1.29 ansicolor"
Code language: PHP (php)
Here is docker-compose.yaml
for running Jenkins Controller with two Jenkins Agents in Docker containers. Count of agents is limited by VPS (or server) CPU and memory limits.
version: '3.8'
networks:
jenkins:
external: true
services:
jenkins:
#image: jenkins/jenkins:lts
build: ./build/controller/
networks:
- jenkins
privileged: true
user: root
ports:
- 9000:8080
- 50000:50000
container_name: jenkins
volumes:
- ./jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- DOCKER_HOST=host-gateway
restart: always
jenkins-agent-1:
image: jenkins/ssh-agent:latest-jdk17
container_name: jenkins-agent-1
restart: always
networks:
- jenkins
environment:
- JENKINS_AGENT_SSH_PUBKEY=ssh-rsa AAAA...== bvn13@bvn13-workbook # paste public key here
jenkins-agent-2:
image: jenkins/ssh-agent:latest-jdk17
container_name: jenkins-agent-2
restart: always
networks:
- jenkins
environment:
- JENKINS_AGENT_SSH_PUBKEY=ssh-rsa AAAA...== bvn13@bvn13-workbook # paste public key here
Code language: PHP (php)
rebuild.sh
content:
#!/bin/env bash
docker-compose down
docker-compose up -d --build --force-recreate
Code language: JavaScript (javascript)
Jenkins setup steps
1. Please refer the post-installation setup wizard on Jenkins official documentation page to setup Jenkins properly.
2. Next step is to add agents into controller.
Hints:
- Create credentials for accessing to Agents by adding private key as a pair to the very public key specified in
docker-compose.yaml
for agents few steps earlier - Agent’s host name is docker container name specified into
docker-compose.yaml
few steps earlier
3. Next – add Host as Jenkins agent
Hints:
- Remote root path shall be specified as a directory under your user’s home directory otherwise Jenkins cannot access it:
/home/{USER}/jenkins-agent
- Connection to Host shall be
ssh
- Host IP is
172.17.0.1
– Docker HOST IP - Provide the credentials to Host system – please generate another key pair for this step. Public key shall be specified as approved one in
~/.ssh/authorized_keys
file. Private key shall be added in Jenkins credentials

Spring Cloud Eureka
Spring Cloud Eureka is an application that must run between services to coordinate their communications.
Spring Admin Panel
Spring boot admin provides an admin interface for Spring Boot web applications which expose actuator endpoints. It provides the possibility to look after services (health), their metrics, logs and others actuator endpoints.

Spring Cloud Config Server
Spring Cloud Config Server is intended for externalizing configuration. I take the main feature Spring Cloud Config Server provides to be the possibility to update properties of a service without the need to rebuild or even reboot service.