From 49cef7098c94d27c6286f22c462935383a86d69e Mon Sep 17 00:00:00 2001 From: Joao Date: Fri, 6 Feb 2026 06:18:04 +0000 Subject: [PATCH] Initial: C# .NET 8 API + Dockerfile + Pipeline + K8s manifests --- .gitignore | 5 ++++ .woodpecker.yml | 27 +++++++++++++++++ DemoApi.csproj | 5 ++++ Dockerfile | 13 ++++++++ Program.cs | 13 ++++++++ k8s/deployment.yaml | 73 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 136 insertions(+) create mode 100644 .gitignore create mode 100644 .woodpecker.yml create mode 100644 DemoApi.csproj create mode 100644 Dockerfile create mode 100644 Program.cs create mode 100644 k8s/deployment.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2789d71 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +*.user +*.suo +.vs/ diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..654a659 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,27 @@ +when: + - event: push + branch: main + +steps: + - name: build + image: mcr.microsoft.com/dotnet/sdk:8.0 + commands: + - dotnet restore + - dotnet build --no-restore + - dotnet publish -c Release -o /tmp/publish --no-restore + + - name: docker + image: plugins/docker + settings: + registry: registry.ci-cd.svc.cluster.local:5000 + repo: registry.ci-cd.svc.cluster.local:5000/demo/demo-api + tags: + - latest + - ${CI_COMMIT_SHA:0:8} + insecure: true + + - name: deploy + image: bitnami/kubectl:latest + commands: + - kubectl set image deployment/demo-api api=registry.ci-cd.svc.cluster.local:5000/demo/demo-api:${CI_COMMIT_SHA:0:8} -n apps || echo "First deploy - will create" + - kubectl rollout status deployment/demo-api -n apps --timeout=60s || true diff --git a/DemoApi.csproj b/DemoApi.csproj new file mode 100644 index 0000000..f577589 --- /dev/null +++ b/DemoApi.csproj @@ -0,0 +1,5 @@ + + + net8.0 + + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8b58b65 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src +COPY *.csproj . +RUN dotnet restore +COPY . . +RUN dotnet publish -c Release -o /app + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 +WORKDIR /app +COPY --from=build /app . +EXPOSE 5000 +ENV ASPNETCORE_URLS=http://+:5000 +ENTRYPOINT ["dotnet", "DemoApi.dll"] diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..9b1b41e --- /dev/null +++ b/Program.cs @@ -0,0 +1,13 @@ +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapGet("/", () => new { + service = "demo-api", + version = "1.0.0", + hostname = Environment.MachineName, + timestamp = DateTime.UtcNow +}); + +app.MapGet("/health", () => Results.Ok(new { status = "healthy" })); + +app.Run("http://0.0.0.0:5000"); diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 0000000..e2a0fe4 --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: demo-api + namespace: apps +spec: + replicas: 2 + selector: + matchLabels: + app: demo-api + template: + metadata: + labels: + app: demo-api + spec: + containers: + - name: api + image: registry.ci-cd.svc.cluster.local:5000/demo/demo-api:latest + ports: + - containerPort: 5000 + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + memory: 256Mi + livenessProbe: + httpGet: + path: /health + port: 5000 + initialDelaySeconds: 10 + readinessProbe: + httpGet: + path: /health + port: 5000 + initialDelaySeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: demo-api + namespace: apps +spec: + selector: + app: demo-api + ports: + - port: 80 + targetPort: 5000 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: demo-api + namespace: apps + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod +spec: + ingressClassName: traefik + rules: + - host: api.136.248.82.18.nip.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: demo-api + port: + number: 80 + tls: + - hosts: + - api.136.248.82.18.nip.io + secretName: demo-api-tls