Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
test
__pycache__/
*.py[cod]
venv/
__MACOSX/
*.log

.vscode/
.idea/

.obsidian

.DS_Store
.env
13 changes: 13 additions & 0 deletions app_go/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Build outputs
devops-info-service
*.exe
*.out

# Git / editor / OS
.git/
.DS_Store
.idea/
.vscode/

# Docs/tests not needed in image build context (optional)
docs/
35 changes: 35 additions & 0 deletions app_go/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# syntax=docker/dockerfile:1

# --- Stage 1: Builder ---
FROM golang:1.23.5-alpine3.21 AS builder

WORKDIR /src

# Cache deps first
COPY go.mod ./
RUN go mod download

# Copy source
COPY main.go ./

# Build a static binary (smaller + easier to run in minimal images)
ARG TARGETOS
ARG TARGETARCH

RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH:-arm64} \
go build -trimpath -ldflags="-s -w" -o /out/devops-info-service .

# --- Stage 2: Runtime (minimal, non-root) ---
FROM gcr.io/distroless/static-debian12:nonroot AS runtime

WORKDIR /app

COPY --from=builder /out/devops-info-service /app/devops-info-service

EXPOSE 8080

ENV HOST=0.0.0.0 \
PORT=8080

# distroless:nonroot already runs as nonroot
ENTRYPOINT ["/app/devops-info-service"]
53 changes: 53 additions & 0 deletions app_go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# DevOps Info Service (Go) — Bonus Task

## Overview
A Go implementation of the DevOps Info Service. It provides two endpoints:
- `GET /` returns service/system/runtime/request information in JSON
- `GET /health` returns a simple health status JSON

## Prerequisites
- Go installed (check with `go version`)

## Run (from source)
```bash
go run .
```
By default the service listens on `0.0.0.0:8080`.

### Custom configuration

```bash
HOST=127.0.0.1 PORT=9090 go run .
```

## Build (binary)

```bash
go build -o devops-info-service
```

## Run (binary)

```bash
./devops-info-service
```

### Custom configuration (binary)

```bash
HOST=127.0.0.1 PORT=9090 ./devops-info-service
```

## API Endpoints

### GET /

```bash
curl -s http://127.0.0.1:8080/ | python -m json.tool
```

### GET /health

```bash
curl -s http://127.0.0.1:8080/health | python -m json.tool
```
Binary file added app_go/devops-info-service
Binary file not shown.
7 changes: 7 additions & 0 deletions app_go/docs/GO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Why Go (Compiled Language)

I chose Go for the compiled-language bonus task because:
- Go compiles into a single binary, which is convenient for deployment.
- It has a minimal standard library for building HTTP services (`net/http`).
- It’s fast to build and run and is commonly used in infrastructure/DevOps tooling.
- Small, self-contained binaries work well with Docker multi-stage builds in later labs.
49 changes: 49 additions & 0 deletions app_go/docs/LAB01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# LAB01 — Bonus Task (Go)

## Implemented Endpoints
- `GET /` — returns service, system, runtime, request info + endpoints list (JSON)
- `GET /health` — returns health status + timestamp + uptime_seconds (JSON)

The JSON structure matches the Python version (same top-level fields and same key layout inside each section).

## How to Run (from source)
```bash
go run .
```
#### Test:

```bash
curl -s http://127.0.0.1:8080/ | python -m json.tool curl -s http://127.0.0.1:8080/health | python -m json.tool
```

## How to Build and Run (binary)

#### Build:

```bash
go build -o devops-info-service ls -lh devops-info-service
```

#### Run:

```bash
./devops-info-service
```

#### Test binary:

```bash
curl -s http://127.0.0.1:8080/health | python -m json.tool
```

## Screenshots

Screenshots are stored in `docs/screenshots/`:

Recommended set:
- `01-go-run.png` — running from source (`go run .`)
- `02-main-endpoint.png` — `GET /` output
- `03-health-endpoint.png` — `GET /health` output
- `04-go-build.png` — `go build` + `ls -lh` showing binary size
- `05-binary-run.png` — running compiled binary (`./devops-info-service`)
- `06-binary-health.png` — health check from binary run
146 changes: 146 additions & 0 deletions app_go/docs/LAB02.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# LAB02 (Bonus) — Multi-Stage Docker Build (Go)

This document explains how I containerized the compiled Go application using a **multi-stage Docker build** to minimize the final image size and reduce the runtime attack surface. 

---

## Multi-Stage Strategy

### Stage 1 — Builder

- **Image:** `golang:1.23.5-alpine3.21`

- **Purpose:** provides the Go toolchain needed to compile the application.

- **Output artifact:** a single Linux binary at `/out/devops-info-service`.


Key choices and why they matter:

- **Dependency caching:** `go mod download` runs right after copying `go.mod`, before copying source code.
This means dependency download is cached and not repeated on every code change.

- **Static binary:** `CGO_ENABLED=0` builds a static binary, which makes it suitable for minimal runtime images.

- **Smaller binary:** `-ldflags="-s -w"` strips debug symbols to reduce binary size.


### Stage 2 — Runtime

- **Image:** `gcr.io/distroless/static-debian12:nonroot`

- **Purpose:** run only the binary (no shell, no package manager, minimal filesystem).

- **Security benefit:** default **non-root** user and fewer components installed → smaller attack surface.


---

## Size Comparison (builder vs final)

Final image size from `docker images`:

```
REPOSITORY TAG IMAGE ID CREATED SIZE
lab02-go latest 0f3bc22c104c 2 minutes ago 13.4MB
lab02-go-builder latest a52c4160b20d 2 minutes ago 468MB
```


**Analysis:**
The multi-stage Go image is much smaller because the final runtime stage contains only the compiled binary and a minimal runtime filesystem. The builder stage contains the full Go toolchain and is not shipped.

---

## Dockerfile Walkthrough

Key parts of the Dockerfile and purpose:

```dockerfile
FROM golang:1.23.5-alpine3.21 AS builder
WORKDIR /src

COPY go.mod ./
RUN go mod download
```

- Copies only `go.mod` first and downloads dependencies → maximizes Docker layer caching.


```dockerfile
COPY main.go ./

ARG TARGETOS
ARG TARGETARCH

RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH:-arm64} \
go build -trimpath -ldflags="-s -w" -o /out/devops-info-service .
```

- Copies the source and compiles a **static** binary.

- Uses `TARGETOS/TARGETARCH` to build correctly on different platforms (important on Apple Silicon / arm64).


```dockerfile
FROM gcr.io/distroless/static-debian12:nonroot AS runtime
WORKDIR /app
COPY --from=builder /out/devops-info-service /app/devops-info-service
EXPOSE 8080 ENV HOST=0.0.0.0 PORT=8080
ENTRYPOINT ["/app/devops-info-service"]
```

- Distroless runtime is minimal and runs as non-root.

- Only the binary is copied into the final image.

- Port and env vars match the app defaults.


---

## Build & Run Evidence

### Build

```shell
docker build -t lab02-go -f app_go/Dockerfile app_go [+]
Building ... FINISHED
=> naming to docker.io/library/lab02-go:latest
```

### Run

```shell
docker run --rm -p 8080:8080 lab02-go
```

### Test endpoints

```shell
curl http://localhost:8080/
# returned JSON with service/system/runtime/request information
```

(Optionally)

```shell
curl http://localhost:8080/health
```

---

## Why Multi-Stage Builds Matter (Compiled Languages)

- **Smaller images:** faster pulls, less storage, faster deploys (final image is ~13.4MB).

- **Security:** runtime image excludes compilers, shells, package managers → fewer vulnerabilities and lower attack surface.

- **Clear separation:** build-time vs run-time concerns are isolated.


Trade-offs:

- Dockerfile becomes slightly more complex.

- Debugging inside distroless containers is harder (no shell), so logs/metrics are preferred.
Binary file added app_go/docs/screenshots/01-go-run.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app_go/docs/screenshots/02-main-endpoint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app_go/docs/screenshots/03-health-endpoint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app_go/docs/screenshots/04-go-build.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app_go/docs/screenshots/05-binary-run.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app_go/docs/screenshots/06-binary-health.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions app_go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module devops-info-service-go

go 1.23
Loading