DevOps Flow¶
This document explains the complete flow of your code from your local machine to running in production on our Kubernetes cluster. Understanding this distinction between local and remote execution is crucial for working effectively with CI/CD pipelines.
Key Concepts: Local vs Remote¶
Local (Your Laptop)¶
- You write and test code here
- You use
gitto commit and push changes - Running
mvnor Docker locally tests on your machine only - Changes here don't affect the game running on the server
Remote (Our Servers)¶
- GitLab server stores your code
- GitLab Runners build your code automatically
- Container images are stored in the registry
- Kubernetes cluster runs the actual game
Important: When you push code to GitLab, it doesn't run on your laptop anymore. The CI/CD pipeline runs on our runners, and the final application runs in our Kubernetes cluster.
Complete CI/CD Flow¶
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#e8f4f8','primaryTextColor':'#000','primaryBorderColor':'#0066cc','lineColor':'#0066cc','secondaryColor':'#fff4e6','tertiaryColor':'#f0f0f0','fontSize':'14px'}}}%%
graph TB
subgraph Local["🏠 LOCAL ENVIRONMENT"]
direction TB
Dev["👨💻 You (Developer)<br/>Write Java code<br/>Test locally"]
LocalGit["📁 Local Git Repository<br/>.git folder"]
Dev -->|"1. git commit"| LocalGit
end
subgraph Remote["🌐 REMOTE ENVIRONMENT"]
direction TB
GitLab["🦊 GitLab Server<br/>Stores your code<br/>Manages CI/CD"]
subgraph Runner["⚙️ GitLab Runner"]
direction TB
Build["📦 Build Job<br/>mvn package<br/>Jib builds image"]
Test["✅ Test Job<br/>mvn test"]
Deploy["🚀 Deploy Job<br/>kubectl apply"]
end
Registry["📦 Container Registry<br/>Stores Docker images<br/>gitlab.stud.atlantis.ugent.be:5050"]
subgraph K8s["☸️ Kubernetes Cluster"]
direction TB
Pods["🎮 Your Running Pods<br/>Actual game instances"]
end
end
%% Flow connections
LocalGit ==>|"2. git push"| GitLab
GitLab -->|"3. Triggers pipeline"| Runner
Build -->|"4. Pushes image"| Registry
Build -.->|"on success"| Test
Test -.->|"on success"| Deploy
Deploy -->|"5. kubectl apply<br/>(updates deployment)"| K8s
K8s -->|"6. Pulls new image"| Registry
%% Styling
classDef localStyle fill:#e8f4f8,stroke:#0066cc,stroke-width:3px
classDef remoteStyle fill:#fff4e6,stroke:#ff9900,stroke-width:2px
classDef runnerStyle fill:#f0f0f0,stroke:#666,stroke-width:2px
classDef k8sStyle fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
class Local localStyle
class Remote,GitLab,Registry remoteStyle
class Runner,Build,Test,Deploy runnerStyle
class K8s,Pods k8sStyle
Understanding Each Step¶
-
Local Development (
git push)- You write code on your laptop in your IDE
- You commit changes with
git commit - You push to GitLab with
git push - Nothing runs yet! Code is just uploaded to GitLab
-
Pipeline Trigger
- GitLab detects the push
- Automatically starts your
.gitlab-ci.ymlpipeline - Assigns jobs to available GitLab Runners
-
Build Phase (in Runner container)
- Runner creates a fresh Docker container with JDK
- Downloads your code from GitLab
- Downloads Maven dependencies
- Runs
mvn packageto compile your Java code - Uses Jib to build a Docker image
- Pushes the image to the Container Registry
- This is NOT on your laptop! It's on our runner servers
-
Test Phase (in Runner container)
- New container is created
- Runs your unit and integration tests
- If tests fail, pipeline stops here
-
Deploy Phase (in Runner container)
- Runner executes
kubectl applycommands - Sends deployment instructions to Kubernetes cluster
- Still not on your laptop! Runner talks to Kubernetes
- Runner executes
-
Kubernetes Deployment
- Kubernetes receives the deployment update
- Pulls the new Docker image from the Registry
- Stops old pods, starts new pods with your updated code
- Your code is now running in the game!
Kubernetes Cluster Architecture¶
Our Kubernetes cluster consists of 3 control plane nodes and 3 worker nodes. Here's how it's organized:
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#e6f3ff','primaryTextColor':'#000','primaryBorderColor':'#0066cc','lineColor':'#666','fontSize':'14px'}}}%%
graph TB
subgraph Cluster["☸️ IDLab Kubernetes Cluster"]
direction TB
ControlPlane["🎛️ Control Plane<br/>(3 nodes for high availability)<br/><br/>• API Server<br/>• Scheduler<br/>• Controller Manager"]
subgraph Workers["👷 Worker Nodes (3 nodes)"]
direction LR
Worker1["Worker Node 1<br/><br/>🎮 Team pods<br/>(your applications)<br/><br/>🎮 Backend"]
Worker2["Worker Node 2<br/><br/>🎮 Team pods<br/>(your applications)<br/><br/>🎮 Frontend"]
Worker3["Worker Node 3<br/><br/>🎮 Team pods<br/>(your applications)<br/><br/>🎮 Monitoring"]
end
end
kubectl["💻 kubectl<br/>(from CI/CD)"]
Registry2["📦 Container Registry"]
kubectl -->|"kubectl apply"| ControlPlane
ControlPlane -->|"schedules pods on"| Workers
Worker1 -.->|"pulls images"| Registry2
Worker2 -.->|"pulls images"| Registry2
Worker3 -.->|"pulls images"| Registry2
classDef controlStyle fill:#fff4e6,stroke:#ff9900,stroke-width:3px
classDef workerStyle fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
class ControlPlane controlStyle
class Workers,Worker1,Worker2,Worker3 workerStyle
Cluster Components Explained¶
Control Plane (3 nodes for high availability)
- API Server: Receives commands from
kubectlin your CI/CD pipeline - Scheduler: Decides which worker node should run each pod
- Controller Manager: Ensures desired state matches actual state (e.g., if a pod crashes, it restarts it)
- 3 nodes provide redundancy - if one fails, the others keep working
Worker Nodes (3 nodes for running applications)
- Each worker node can run multiple pods
- Each pod contains one or more Docker containers
- Your
logic-serviceruns as a pod on one of these workers - Kubernetes automatically distributes pods across workers depending on availability and load
Key Point: When you run kubectl apply in your CI/CD pipeline:
- Command goes to the Control Plane
- Control Plane schedules your pod on a worker node
- Worker node pulls your Docker image from the registry
- Your application starts running in a pod
Common Misconceptions¶
"When I push to GitLab, my code runs on GitLab"¶
Reality: GitLab stores your code. The CI/CD pipeline runs on GitLab Runners (separate machines), and your final application runs in the Kubernetes cluster.
"If it works on my laptop, it will work in Kubernetes"¶
Reality: Your laptop and Kubernetes are different environments. Always test using the CI/CD pipeline. Environment variables, networking, and resource limits differ.
"The Docker image is built on my machine"¶
Reality: When using CI/CD, the image is built by the GitLab Runner in a container on our servers, not on your laptop.
"kubectl commands in my CI/CD affect my local machine"¶
Reality: kubectl in CI/CD connects to the remote Kubernetes cluster using the KUBECONFIG credentials. It never touches your laptop.
Quick Reference: Where Does What Run?¶
| Activity | Where It Happens | Tool/Command |
|---|---|---|
| Writing code | Your laptop | IDE (IntelliJ, VSCode) |
| Running code locally | Your laptop | mvn quarkus:dev |
| Storing code | GitLab Server | git push |
| Building in CI/CD | GitLab Runner | .gitlab-ci.yml |
| Storing images | Container Registry | Jib/Docker |
| Running the game | Kubernetes Cluster | kubectl apply |
| Viewing logs | Kubernetes Cluster | kubectl logs |
What Happens When You Change Code?¶
%%{init: {'theme':'base'}}%%
sequenceDiagram
actor Dev as 👨💻 You
participant Laptop as 🏠 Your Laptop
participant GitLab as 🦊 GitLab
participant Runner as ⚙️ Runner
participant Registry as 📦 Registry
participant K8s as ☸️ Kubernetes
Dev->>Laptop: 1. Edit Java file
Dev->>Laptop: 2. git commit
Dev->>GitLab: 3. git push
Note over GitLab: Code stored on GitLab server
GitLab->>Runner: 4. Start pipeline
Note over Runner: Fresh container created
Runner->>Runner: 5. mvn package (build)
Runner->>Registry: 6. Push Docker image
Runner->>K8s: 7. kubectl apply
Note over K8s: Old pod terminated
K8s->>Registry: 8. Pull new image
K8s->>K8s: 9. Start new pod
Note over K8s: Your updated code is now running!
Dev->>K8s: 10. kubectl logs (check if it works)
Remember: Steps 4-9 happen entirely on remote servers. Your laptop is only involved in steps 1-3 and 10!