From f60610d65cb5880a99e86452becdb831ec731d2a Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 11 Aug 2024 19:33:54 +0300 Subject: feat!: Major rework of DevOps components --- .github/workflows/dev-branch.yml | 2 +- .github/workflows/main-branch.yml | 6 +- .github/workflows/main-pr.yml | 14 +++++ Dockerfile | 10 ---- Dockerfile.dev | 10 ---- README.md | 65 ++++++++++++++------- demo-production-server-deployment.yaml | 70 ----------------------- docker-compose.yml | 5 -- docker/dev/Dockerfile | 10 ++++ docker/docker-compose.yml | 5 ++ docker/prod/Dockerfile | 10 ++++ kubernetes/demo-production-server-deployment.yaml | 70 +++++++++++++++++++++++ 12 files changed, 157 insertions(+), 120 deletions(-) create mode 100644 .github/workflows/main-pr.yml delete mode 100644 Dockerfile delete mode 100644 Dockerfile.dev delete mode 100644 demo-production-server-deployment.yaml delete mode 100644 docker-compose.yml create mode 100644 docker/dev/Dockerfile create mode 100644 docker/docker-compose.yml create mode 100644 docker/prod/Dockerfile create mode 100644 kubernetes/demo-production-server-deployment.yaml diff --git a/.github/workflows/dev-branch.yml b/.github/workflows/dev-branch.yml index 95d580a..7198d8e 100644 --- a/.github/workflows/dev-branch.yml +++ b/.github/workflows/dev-branch.yml @@ -86,5 +86,5 @@ jobs: with: push: true context: . - file: Dockerfile.dev + file: ./docker/dev/Dockerfile tags: ${{ secrets.DOCKERHUB_USERNAME }}/pico-web-dev:latest diff --git a/.github/workflows/main-branch.yml b/.github/workflows/main-branch.yml index f19976d..9c933ef 100644 --- a/.github/workflows/main-branch.yml +++ b/.github/workflows/main-branch.yml @@ -5,7 +5,7 @@ on: - main jobs: Build-docker-and-push: - name: Build the docker container image and push it to dockerhub + name: Build the production docker container image and push it to dockerhub runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -18,6 +18,8 @@ jobs: - uses: docker/build-push-action@v5 with: push: true + context: . + file: ./docker/prod/Dockerfile tags: ${{ secrets.DOCKERHUB_USERNAME }}/pico-web-server:latest Release: @@ -30,4 +32,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }} with: - bump_version_scheme: minor + bump_version_scheme: norelease # PR must have one of these labels: release:major, release:minor, release:patch diff --git a/.github/workflows/main-pr.yml b/.github/workflows/main-pr.yml new file mode 100644 index 0000000..c122af8 --- /dev/null +++ b/.github/workflows/main-pr.yml @@ -0,0 +1,14 @@ +name: Check for release label inside pull request +on: + pull_request: + types: [opened, edited, ready_for_review, review_requested] + branches: + - 'main' +jobs: + has_release_label: + if: ! contains(github.event.pull_request.labels.*.name, 'release:major') && + ! contains(github.event.pull_request.labels.*.name, 'release:minor') && + ! contains(github.event.pull_request.labels.*.name, 'release:patch') + runs-on: ubuntu-latest + steps: + - run: exit 1 diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index e850445..0000000 --- a/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM alpine:latest - -RUN apk update && apk upgrade -RUN apk add musl-dev gcc make - -COPY ./src /usr/src -RUN make -C /usr/src prod-server - -EXPOSE 8080 -ENTRYPOINT [ "/usr/build/server", "0.0.0.0,8080" ] diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index 328f4a6..0000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,10 +0,0 @@ -FROM alpine:latest - -RUN apk update && apk upgrade -RUN apk add bash musl-dev gcc make gdb - -COPY ./build /usr/build - -EXPOSE 8080 -WORKDIR /usr/build -CMD /bin/bash diff --git a/README.md b/README.md index be2b15b..67fa1f5 100644 --- a/README.md +++ b/README.md @@ -3,42 +3,63 @@ Small client-server application. The server receives a URL from a client and returns the appropriate page. -URIs (URLs) are in the form `userinfo@address:portPATH`, where `address` and `port` could be skipped. -The userinfo section is analogous to subdomains in normal web applications. +## DevOps lifecycle -It's assumed that all pages are written in Markdown so the client adds special "rendering" like hyperlinks and bold text (via ANSI escape sequences). -The server is configured to send pages only in allowed directories, and can handle multiple directories with custom error pages. +### 1. Plan -## From issue to production +With [GitHub issues](https://github.com/Syndamia/pico-web/issues) modifications to the project are started and discussed -![image](https://github.com/Syndamia/pico-web/assets/46843671/d7ae678a-e813-45c6-afa6-9acf05129e88) +### 2. Code -1. A [GitHub issue](https://github.com/Syndamia/pico-web/issues) is created when something needs to be added/changed in the project -2. Then a developer makes the appropriate branch (which I call the "feature branch"), where they push updates to the codebase. - On every commit a small pipeline is ran, executing all tests and static analysis. -3. Upon completion, a merge request is made to the `dev` branch. After the GitHub workflow is successful and a mandatory review, it will be merged. -4. Then, on the new commit, a new workflow is started on the `dev` branch, doing again the tests and static analysis, alongside the security analysis. - Afterwards, the development binaries are built and the [development Docker image](https://hub.docker.com/r/syndamia/pico-web-dev) is deployed. -5. After enough changes have accumulated, another pull request is made, from `dev` to `main` (PRs to `main` are only done from `dev`). - On successful workflow and mandatory review, the changes can be merged. -6. Finally, a pipeline from the `main` branch will be ran, deploying the [production server Docker image](https://hub.docker.com/r/syndamia/pico-web-server) and creating a new GitHub release. +Our branching strategy is a "feature workflow with stable branches", meaning: -Although there is no deployment to a managed kubernetes cluster (too expensive), a Deployment with the [demo](./demo) files is available: +- a feature branch is created for each issue +- after the issue is resolved in that branch, it is merged into the `dev` branch +- after enough time has passed, the `dev` branch is merged into the `main` branch -```bash -kubectl apply -f demo-production-server-deployment.yaml -``` +You must only push commits to feature branches. +Code can be added to `dev` only via pull requests from feature branches. +Code can be added to `main` only via pull requests from `dev`. + +Merge requests must always be approved by a contributor and `dev` merge requests to `main` must always have one of these labels: `release:major`, `release:minor` or `release:patch`. + +### 3. CI + +On each push to feature branches and `dev` we execute the "feature-branch" pipeline, during which we run: + +- SAST: unit tests, [clang](TODO)'s `--analyze` static analysis and [flawfinder](TODO)'s security analysis + +- the `Makefile` for building our application -## Building and usage +### 4. CD -Build the binaries: +On each successful merge request to `dev`, + +- a development docker image is deployed to [dockerhub](https://hub.docker.com/r/syndamia/pico-web-dev) and +- the development Kubernetes cluster is deployed with [minikube](TODO) in the pipeline + +On each successful merge request to `main`, + +- the production docker image is deployed to [dockerhub](https://hub.docker.com/r/syndamia/pico-web), +- the production Kubernetes cluster is deployed with [minkube](TODO) in the pipeline and +- a [GitHub release](https://github.com/Syndamia/pico-web/releases) is created, according to the pull request label ```bash -make +kubectl apply -f demo-production-server-deployment.yaml ``` +## Project details + You get two binaries, `server` and `browser`. +URIs (URLs) are in the form `userinfo@address:portPATH`, where `address` and `port` could be skipped. +The userinfo section is analogous to subdomains in normal web applications. + +It's assumed that all pages are written in Markdown so the client adds special "rendering" like hyperlinks and bold text (via ANSI escape sequences). +The server is configured to send pages only in allowed directories, and can handle multiple directories with custom error pages. + ### Browser The `browser` program takes no arguments. diff --git a/demo-production-server-deployment.yaml b/demo-production-server-deployment.yaml deleted file mode 100644 index 62e140d..0000000 --- a/demo-production-server-deployment.yaml +++ /dev/null @@ -1,70 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pico-web-server-deployment -spec: - strategy: - type: RollingUpdate - replicas: 3 - selector: - matchLabels: - app: pico-web-server-pod - template: - metadata: - name: pico-web-server-pod - labels: - environment: production - app: pico-web-server-pod - spec: - containers: - - name: pico-web-server-prod - image: syndamia/pico-web-server:latest - args: [ 'demo,/usr/share/demo/,page.md' ] - ports: - - containerPort: 8080 - volumeMounts: - - name: demo-ps - mountPath: /usr/share/demo - volumes: - - name: demo-ps - persistentVolumeClaim: - claimName: demo-pvc ---- -apiVersion: v1 -kind: Service -metadata: - name: pico-web-server-service -spec: - type: NodePort - selector: - app: pico-web-server-pod - ports: - - protocol: TCP - port: 8080 - targetPort: 8080 ---- -apiVersion: v1 -kind: PersistentVolume -metadata: - name: demo-pv -spec: - volumeMode: Filesystem - capacity: - storage: 50Mi - accessModes: - - ReadWriteOnce - hostPath: - path: "/tmp/demo" # You'll have to manually copy ./demo to here ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: demo-pvc -spec: - volumeName: demo-pv - storageClassName: "" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Mi diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 661fd21..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - server: - build: . - ports: - - "5000:8080" diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile new file mode 100644 index 0000000..328f4a6 --- /dev/null +++ b/docker/dev/Dockerfile @@ -0,0 +1,10 @@ +FROM alpine:latest + +RUN apk update && apk upgrade +RUN apk add bash musl-dev gcc make gdb + +COPY ./build /usr/build + +EXPOSE 8080 +WORKDIR /usr/build +CMD /bin/bash diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..661fd21 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,5 @@ +services: + server: + build: . + ports: + - "5000:8080" diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile new file mode 100644 index 0000000..e850445 --- /dev/null +++ b/docker/prod/Dockerfile @@ -0,0 +1,10 @@ +FROM alpine:latest + +RUN apk update && apk upgrade +RUN apk add musl-dev gcc make + +COPY ./src /usr/src +RUN make -C /usr/src prod-server + +EXPOSE 8080 +ENTRYPOINT [ "/usr/build/server", "0.0.0.0,8080" ] diff --git a/kubernetes/demo-production-server-deployment.yaml b/kubernetes/demo-production-server-deployment.yaml new file mode 100644 index 0000000..62e140d --- /dev/null +++ b/kubernetes/demo-production-server-deployment.yaml @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pico-web-server-deployment +spec: + strategy: + type: RollingUpdate + replicas: 3 + selector: + matchLabels: + app: pico-web-server-pod + template: + metadata: + name: pico-web-server-pod + labels: + environment: production + app: pico-web-server-pod + spec: + containers: + - name: pico-web-server-prod + image: syndamia/pico-web-server:latest + args: [ 'demo,/usr/share/demo/,page.md' ] + ports: + - containerPort: 8080 + volumeMounts: + - name: demo-ps + mountPath: /usr/share/demo + volumes: + - name: demo-ps + persistentVolumeClaim: + claimName: demo-pvc +--- +apiVersion: v1 +kind: Service +metadata: + name: pico-web-server-service +spec: + type: NodePort + selector: + app: pico-web-server-pod + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: demo-pv +spec: + volumeMode: Filesystem + capacity: + storage: 50Mi + accessModes: + - ReadWriteOnce + hostPath: + path: "/tmp/demo" # You'll have to manually copy ./demo to here +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: demo-pvc +spec: + volumeName: demo-pv + storageClassName: "" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi -- cgit v1.2.3