3. Setting Up a Service
This guide walks you through a simple web service using the newly installed Kubernetes agent, runner, GitLab CI/CD pipeline, and a deployment YAML manifest.
Notes#
Some more screenshots wouldn't hurt.
As of October 23rd, 2025 this guide uses an image built from a fork of Narsu's apache-test, if that is turned into an "official" repository then updates need to be made here.
Introduction#
This document walks through installing a simple web service using the newly installed Kubernetes agent, runner, GitLab CI/CD pipeline, and a deployment YAML manifest.
As an example, we will deploy a basic Apache HTTP server.
Prerequisites#
- The product platform instructions v2 steps 1 and 2 have been reviewed.
- A Kubernetes agent connected to the project’s cluster is set up.
- Runner installed and registered on a cPouta VM.
Setting up a simple service#
First, you need to find your cPouta virtual machine's domain name. You can find your virtual machine's floating IP on CSC cPouta web dashboard, or by simply following the couple of steps in Installing MicroK8s on Rocky Linux guide.
[rocky@microk8s-master ~]$ nslookup <Your cPouta VM floating IP>
136.252.50.86.in-addr.arpa name = fip-AAA-BBB-CCC-DDD.kaj.poutavm.fi.
136.252.50.86.in-addr.arpa name = vmXXXX.kaj.pouta.csc.fi.
NOTE: vmXXXX.kaj.pouta.csc.fi is now deprecated, do not use it anywhere if it still shows up.
Take note of your fip-AAA-BBB-CCC-DDD.kaj.poutavm.fi domain, it will be used soon.
Next, go to GitLab and make a personal fork of apache-test. Once you've done that, you need to start the build pipeline for it. In your forked apache-test project, from the left side panel, choose Build -> Pipelines -> New pipeline -> New pipeline. After a short while apache-test image should be ready to go.
To allow MicroK8s to pull images from a private repository, you need to first add a personal access token (PAT) and then create a Docker registry secret in your cPouta virtual machine, which makes use of that token.
So, in GitLab, click on your profile picture -> Edit profile -> Access tokens -> Add new token. Give the token a name (and a description if you want) and give it read_registry permissions. Save the token you receive. Next, go to your cPouta virtual machine and create the secret with the following:
microk8s kubectl create secret docker-registry gitlab-registry-secret \
--docker-server=gitlab.labranet.jamk.fi:4567 \
--docker-username=<GITLAB-USERNAME> \
--docker-password=<PERSONAL-ACCESS-TOKEN> \
--docker-email=<none or JAMK-EMAIL>
Deployment YAML file#
In the root of the GitLab project where the agent and runner are connected (NOT the forked apache-test), create a .yaml file (e.g. apache-service.yaml). Make sure to add your domain to the ingress section.
To get the apache-test image path, go to your forked apache-test project, from the left panel, choose Deploy -> Container registry -> apache-test and copy the path to latest image. Paste this into the appropriate section in the following .yaml file.
apiVersion: apps/v1
kind: Deployment
metadata:
name: apache
spec:
replicas: 1
selector:
matchLabels:
app: apache
template:
metadata:
labels:
app: apache
spec:
imagePullSecrets:
- name: gitlab-registry-secret # This references the secret created in the previous step
containers:
- name: apache
image: <PATH TO YOUR :latest apache-test IMAGE>
# image: httpd:2.4 # Official Apache image from Docker Hub, use this if image above doesn't work
ports:
- containerPort: 80 # Exposes port 80 inside the container
---
apiVersion: v1
kind: Service
metadata:
name: apache-service
spec:
selector:
app: apache
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP # Internal cluster service (no external exposure by default)
---
# Ingress definition for external access
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: apache-ingress
# annotations: # Uncomment these to enable HTTPS
# cert-manager.io/cluster-issuer: "letsencrypt-prod" # Use Let's Encrypt for certificates
# acme.cert-manager.io/http01-edit-in-place: "true" #
spec:
ingressClassName: nginx
# tls: # Uncomment these to enable HTTPS
# - hosts: #
# - <YOUR-DOMAIN> # Replace with your domain
# secretName: apache-tls # TLS secret name
rules:
- host: <YOUR-DOMAIN>
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: apache-service
port:
number: 80
# Optional: ClusterIssuer for Let's Encrypt (needed if enabling HTTPS)
# apiVersion: cert-manager.io/v1
# kind: ClusterIssuer
# metadata:
# name: letsencrypt-prod
# spec:
# acme:
# server: https://acme-v02.api.letsencrypt.org/directory
# email: your.email@example.com
# privateKeySecretRef:
# name: letsencrypt-prod
# solvers:
# - http01:
# ingress:
# class: nginx
GitLab CI file#
Create a .gitlab-ci.yml file in the root of the same GitLab project as in the previous step (again, NOT the forked apache-test) and add the following configuration.
Make sure to replace values with those specific to your project.
NOTE: Update the KUBE_CONTEXT variable with your own project path and Kubernetes agent name.
It usually looks like YOURSTUDENTID/your-project-name:your-agent-name. If your project is inside a
group, the path would be like your-group-name/your-project-name:your-agent-name.
Use uppercase letters for your student ID, since this variable is case-sensitive!
# Stages for testing, building and deploying the Apache web service
stages:
- test
- deploy
# Include GitLab’s built-in security scanning templates
include:
- template: Security/Dependency-Scanning.gitlab-ci.yml
- template: Security/SAST.gitlab-ci.yml
- template: Security/Secret-Detection.gitlab-ci.yml
- template: Jobs/SAST.gitlab-ci.yml
# Define variables for scans and Kubernetes context
variables:
SAST_DEFAULT_ANALYZERS: eslint, semgrep
DS_DEFAULT_ANALYZERS: retire.js/
KUBE_CONTEXT: YourstudentidOrGroupname/yourprojectname:youragentname
SCAN_KUBERNETES_MANIFESTS: "true"
# Security and dependency scans
sast:
tags:
- general
dependency_scanning:
stage: test
tags:
- general
secret_detection:
stage: test
tags:
- general
# Deploy job – applies the apache-service.yaml manifest to Kubernetes
Deploy:
stage: deploy
image:
name: dtzar/helm-kubectl
entrypoint: [""]
script:
- kubectl config use-context $KUBE_CONTEXT # Switch context to your project’s Kubernetes agent
- kubectl apply -f apache-service.yaml # Deploy the service defined earlier
only:
- main # Runs only on pushes to the main branch
tags:
- general
If the pipeline succeeds and the deployment is successful, you should be able to access your own domain in a browser. Depending on whether you set up HTTP or HTTPS, you should see the Apache welcome page on either of those.

NOTE: This screenshot is misleading when using apache-test container image, needs an update