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
51 changes: 51 additions & 0 deletions app_go/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# VCS
.git
.gitignore

# IDE / editors
.vscode/
.idea/
*.swp

# OS junk
.DS_Store
Thumbs.db

# Docs (not needed for build/run)
docs/
*.md
README*
LICENSE*

# Secrets / env files (NEVER ship)
.env
.env.*

# Logs / reports
*.log
coverage*
*.out
*.prof
*.trace

# Go build artifacts
bin/
dist/
build/
out/
*.exe
*.dll
*.so
*.dylib
*.a
*.o

# Go test cache / tooling caches
**/*_test.go
.golangci.yml
.golangci-lint*
.gotools/
.tmp/
tmp/


8 changes: 8 additions & 0 deletions app_go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Go build outputs
/devops-info-service
*.exe
*.out

# Go tooling
/bin/
/dist/
27 changes: 27 additions & 0 deletions app_go/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# ---------- Stage 1: Build ----------
# Use the full Go toolchain image only for compilation, which will take place in the /app directory
FROM golang:1.25.5-bookworm AS builder
WORKDIR /app

# Copy and install module metadata to use Docker layer caching (if go.sum appears later, this will speed up rebuilding).
COPY go.mod ./
RUN go mod download

# Copy the rest of the source code (excess code is filtered out by .dockerignore) and build the binary
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .

# ---------- Stage 2: Runtime ----------
# Define the runtime environment (only necessary for running the binary).
FROM alpine:3.18

# Create an unprivileged user (does not run as root).
RUN adduser -D appuser

# Create an application directory inside the runtime container and copy the binary from the compilation environment into it (assigning the file to the appuser user)
WORKDIR /app
COPY --from=builder --chown=appuser:appuser /app/myapp .
USER appuser

EXPOSE 5000
CMD ["./myapp"]
246 changes: 246 additions & 0 deletions app_go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
# DevOps Info Service (Lab 01) — Go version

Small Go web app for DevOps labs (extra points).

Provides:
- `GET /` — service/system/runtime/request info + list of endpoints
- `GET /health` — simple health check endpoint (for monitoring / K8s probes)

Configuration is done via environment variables: `HOST`, `PORT`, `DEBUG`.

---

## Overview

This service returns diagnostic information about:
- service metadata (name/version/description/framework)
- host system (hostname/platform/arch/CPU/Go version)
- runtime (uptime + current UTC time)
- current request (client IP, user-agent, method, path)
- available API endpoints (kept as a registry in the app and returned sorted)

---

## Prerequisites

- Go **1.20+** (any modern Go should work)
- No third-party dependencies (standard library only)

---

## Quick Start (go run)
If `go.mod` is missing, you can create it:

```bash
go mod init devops-info-service
```
From the directory containing `main.go`:

Default (0.0.0.0:5000):
```bash
go run .
# or: go run main.go
```

Custom port:
```bash
PORT=8080 go run .
```

Custom host + port:
```bash
HOST=127.0.0.1 PORT=3000 go run .
```

Enable debug-style logging:
```bash
DEBUG=true go run .
```

---

## Build (Binary)

1. Initialize modules (if needed):
```bash
go mod init devops-info-service
go mod tidy
```
2. Build a local binary:
```bash
go build -o devops-info-service .
```
3. Run the binary:
```bash
./devops-info-service
# or with config:
HOST=127.0.0.1 PORT=3000 DEBUG=true ./devops-info-service
```
---

## API Endpoints

### `GET /`

Returns full service + runtime info.

Example:
```bash
curl -s http://127.0.0.1:5000/ | jq '{service, system, runtime, request, endpoints}'
```

Response structure:
```json
{
"service": {
"name": "devops-info-service",
"version": "1.0.0",
"description": "DevOps course info service",
"framework": "Go net/http"
},
"system": {
"hostname": "SerggAidd",
"platform": "linux",
"platform_version": "6.18.5-arch1-1",
"architecture": "amd64",
"cpu_count": 24,
"go_version": "go1.25.5 X:nodwarf5"
},
"runtime": {
"uptime_seconds": 3,
"uptime_human": "0 hour, 0 minutes",
"current_time": "2026-01-23T19:08:17Z",
"timezone": "UTC"
},
"request": {
"client_ip": "127.0.0.1",
"user_agent": "curl/8.18.0",
"method": "GET",
"path": "/"
},
"endpoints": [
{
"method": "GET",
"path": "/",
"description": "Root endpoint: returns service metadata and diagnostic information."
},
{
"method": "GET",
"path": "/health",
"description": "Health check endpoint for monitoring and Kubernetes probes."
}
]
}
```

> Note: JSON object key ordering is not guaranteed by the HTTP/JSON standard.
> Use `python -m json.tool` or `jq` (like in example) only for pretty printing.

---

### `GET /health`

Health endpoint for monitoring / Kubernetes probes.

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

Response:
```json
{
"status": "healthy",
"timestamp": "2026-01-23T19:08:22Z",
"uptime_seconds": 8
}
```

Always returns HTTP **200** when the service is running.

---

## Error Handling

- Unknown routes return JSON 404:

Example:
```bash
curl -s http://127.0.0.1:5000/does-not-exist | python -m json.tool
```

Response:
```json
{
"error": "Not Found",
"message": "Endpoint does not exist"
}
```

- Internal errors return JSON 500 (panic is recovered by middleware):

Example (can be tested by uncommenting the code block with the corresponding endpoint):
```bash
curl -s http://127.0.0.1:5000/crash | python -m json.tool
```

Response:
```json
{
"error": "Internal Server Error",
"message": "An unexpected error occurred"
}
```

---

## Logging

The app logs to **stdout**, which is the recommended approach for Docker/Kubernetes.

Logged events:
- request method/path/client IP/user-agent
- final HTTP status code and request latency
- recovered panics (500) with a short error message

---

## Configuration

| Variable | Default | Description |
|---------:|-----------|-------------|
| `HOST` | `0.0.0.0` | Bind address |
| `PORT` | `5000` | Listen port |
| `DEBUG` | `False` | `true` enables more verbose log flags |

## Docker
Below are the basic commands for building and running an application in a container.

### Local image build
```bash
cd app_go
docker build -t app-go:1.0 .
```

### Starting a container
The container listens on port 5000 internally, so we forward it to the host port (in the case bellow 8080)
```bash
docker run --rm -p 8080:5000 app-go:1.0
```
Example of running with variables:
```bash
docker run --rm -p 8080:5000 -e PORT=5000 -e DEBUG=false app-go:1.0
```
After that you can check endpoints in browser or in defferent terminal:
```bash
curl http://localhost:8080/
curl http://localhost:8080/health
```

### Docker Hub (pull/run)
The image of this container publlished in Docker Hub. Image can be download with the following method:
```bash
docker pull sergey173/app-go:1.0.0
docker run --rm -p 8080:5000 sergey173/app-go:1.0.0
```
Docker Hub repository URL: https://hub.docker.com/repository/docker/sergey173/app-go
28 changes: 28 additions & 0 deletions app_go/docs/GO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Language justification

## Why Go
Go was selected as the implementation language because it offers a strong trade-off for a small, container-oriented HTTP JSON service:
- **Fast implementation**: minimal boilerplate, straightforward concurrency model, and a simple standard toolchain.
- **Standard library coverage**: `net/http`, `encoding/json`, `os`, `runtime`, and `time` are sufficient to implement routing, JSON serialization, environment-based configuration, and uptime without external dependencies.
- **Deployment simplicity**: produces a single static-like executable (depending on build settings), integrates cleanly with Docker/Kubernetes, and favors stdout logging by default.
- **Low operational overhead**: fast startup time and modest memory footprint, which is well-suited for health checks and probe endpoints.
- **Portability**: cross-compilation is first-class and enables easy builds for common targets (e.g., Linux/amd64) from a single development environment.

## Contrast with other compiled languages

### Go vs Rust
Rust provides stronger compile-time guarantees around memory safety, but typically increases development complexity (ownership model, lifetimes) and build friction for small services. For this lab-scale HTTP JSON service, Go achieves the required functionality faster while remaining reliable and maintainable.

### Go vs Java
Java commonly implies a JVM/JRE runtime plus build tooling (Maven/Gradle), which increases packaging complexity and container footprint relative to a single Go binary. For a small service intended for probes/monitoring, Go keeps runtime requirements and deployment steps minimal.

### Go vs C/C++
C/C++ can produce small binaries, but requires manual memory management and often more complex build configuration. Go reduces the likelihood of memory-related defects and simplifies maintenance while still providing compiled performance and simple distribution.

## Trade-offs
- Go provides fewer compile-time memory safety guarantees than Rust.
- Implementing routing/middleware without a third-party framework can require more manual code (though the standard library remains sufficient for the scope of this service).

## Summary
Go was chosen to minimize dependencies and operational complexity while delivering a compact, portable HTTP JSON service suitable for containerized environments. Compared to Rust, Java, and C/C++, Go reduces implementation and deployment overhead for this specific lab task, with trade-offs that are acceptable given the service’s limited scope and reliance on the standard library.

Loading