Prepare the infrastructure

Requirements

  • GitLab;

  • Host to install the GitLab Runner, with:

Installing the GitLab Runner

Follow official instructions to install the GitLab Runner on its dedicated host.

Registering the GitLab Runner

Follow official instructions to register the GitLab Runner in GitLab; set Docker as the executor and any image as the image (e.g., alpine).

Configuring the GitLab Runner

On the GitLab Runner host, open its config.toml configuration file and add the following options to the GitLab Runner you registered earlier:

[[runners]]
  name = "<name of the registered Runner>"
  [runners.docker]
    security_opt = ["seccomp:unconfined", "apparmor:unconfined"]
    volumes = ["/home/build/.werf"]

If the GitLab Runner host runs Linux kernel version 5.12 or lower, install fuse on the host and add one more option to the config.toml file:

[[runners]]
  name = "<name of the registered Runner>"
  [runners.docker]
    devices = ["/dev/fuse"]

You may also want to perform additional configuration of the GitLab Runner.

Configuring the container registry

Enable garbage collection for your container registry.

Preparing the system for cross-platform building (optional)

This step only needed to build images for platforms other than host platform running werf.

Register emulators on your system using qemu-user-static:

docker run --restart=always --name=qemu-user-static -d --privileged --entrypoint=/bin/sh multiarch/qemu-user-static -c "/register --reset -p yes && tail -f /dev/null"

Configure the project

Configuring the GitLab project

Configuring CI/CD of the project

This is how the repository that uses werf for build and deploy might look:

.helm
src
.gitignore
.gitlab-ci.yml
Taskfile.yaml
sources.Dockerfile
werf-giterminism.yaml
werf.yaml
/.werf-deploy-report.json
/.werf-build-report.json
/.werf_secret_key

stages:
  - build
  - test
  - review
  - qa
  - staging-shared
  - staging-apps
  - staging-smoke
  - prod-shared
  - prod-apps
  - prod-smoke
  - cleanup

variables:
  ENABLE_ALL_IMAGES: "false"
  ENABLE_APPS_IMAGES: "false"
  ENABLE_IMAGE_SOURCES: "false"
  WERF_REQUIRE_BUILT_IMAGES: "true"

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
      when: never
    - if: !reference [.rules, if, mr]
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: !reference [.rules, if, tag]
    - if: !reference [.rules, if, main]

default:
  image:
    name: "registry.werf.io/werf/werf:2-stable"
    pull_policy: always
  tags:
    - "<GitLab Runner tag>"

.scripts:
  setup_werf: |
    source "$(werf ci-env gitlab --as-file)"

.rules:
  if:
    main: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    main_schedule: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule"
    main_no_schedule: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule"
    mr: $CI_PIPELINE_SOURCE == "merge_request_event"
    mr_no_schedule: $CI_PIPELINE_SOURCE == "merge_request_event"&& $CI_PIPELINE_SOURCE != "schedule"
    main_or_mr: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_PIPELINE_SOURCE == "merge_request_event"
    main_or_mr_no_schedule: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_PIPELINE_SOURCE == "merge_request_event") && $CI_PIPELINE_SOURCE != "schedule"
    tag: $CI_COMMIT_TAG
    schedule: $CI_PIPELINE_SOURCE == "schedule"
    no_schedule: $CI_PIPELINE_SOURCE != "schedule"

.artifacts:
  deploy_report:
    paths:
      - .werf-deploy-report.json
    expire_in: 1 year
    when: always

.dismiss:
  script:
    - werf dismiss --with-namespace --use-deploy-report
  environment:
    action: stop
  interruptible: false
  timeout: null

.build:
  stage: build
  variables:
    ENABLE_ALL_IMAGES: "true"
  before_script:
    - !reference [.scripts, setup_werf]
  timeout: 30m
  rules:
    - if: !reference [.rules, if, main_or_mr_no_schedule]

images:apps:build:
  extends:
    - .build
  script:
    - werf build app1 app2

image:sources:build:
  extends:
    - .build
  script:
    - werf build sources

.test:simple:
  stage: test
  needs:
    - image:sources:build
  variables:
    ENABLE_IMAGE_SOURCES: "true"
  before_script:
    - !reference [.scripts, setup_werf]

.test:simple:app1:
  extends:
    - .test:simple
  rules:
    - if: !reference [.rules, if, main_or_mr_no_schedule]
      changes:
        - "*"
        - ".helm/**/**"
        - "src/app1/**/**"

.test:simple:app2:
  extends:
    - .test:simple
  rules:
    - if: !reference [.rules, if, main_or_mr_no_schedule]
      changes:
        - "*"
        - ".helm/**/**"
        - "src/app2/**/**"

app1:lint:
  extends:
    - .test:simple:app1
  script:
    - werf kube-run sources -- go-task -d src/app1 lint
  timeout: 5m

app1:unit:
  extends:
    - .test:simple:app1
  script:
    - werf kube-run sources -- go-task -d src/app1 test:unit
  coverage: '/Code coverage is \d+\.\d+/'
  timeout: 15m

app1:integration:
  extends:
    - .test:simple:app1
  script:
    - werf kube-run sources -- go-task -d src/app1 test:integration
  coverage: '/Code coverage is \d+\.\d+/'
  timeout: 30m

app2:lint:
  extends:
    - .test:simple:app2
  script:
    - werf kube-run sources -- go-task -d src/app2 lint
  timeout: 5m

app2:unit:
  extends:
    - .test:simple:app2
  script:
    - werf kube-run sources -- go-task -d src/app2 test:unit
  coverage: '/Code coverage is \d+\.\d+/'
  timeout: 15m

app2:integration:
  extends:
    - .test:simple:app2
  script:
    - werf kube-run sources -- go-task -d src/app2 test:integration
  coverage: '/Code coverage is \d+\.\d+/'
  timeout: 30m

.test:complex:
  stage: test
  needs:
    - images:apps:build
    - image:sources:build
  variables:
    ENABLE_ALL_IMAGES: "true"
    WERF_SET_TAGS_RELEASE: "tags.release=true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf converge --save-deploy-report
  resource_group: ${CI_ENVIRONMENT_SLUG}
  artifacts: !reference [.artifacts, deploy_report]

e2e:short:
  extends:
    - .test:complex
  variables:
    WERF_SET_TAGS_E2E_SHORT: "tags.e2e-short=true"
  environment:
    name: e2e-short/${CI_PIPELINE_IID}
    on_stop: e2e:short:remove
  interruptible: true
  rules:
    - if: !reference [.rules, if, mr_no_schedule]

e2e:short:remove:
  extends:
    - e2e:short
    - .dismiss
  needs:
    - e2e:short
  rules:
    - if: !reference [.rules, if, mr_no_schedule]
      when: always
      allow_failure: true

e2e:long:
  extends:
    - .test:complex
  variables:
    WERF_SET_TAGS_E2E_LONG: "tags.e2e-long=true"
  environment:
    name: e2e-long/${CI_PIPELINE_IID}
    on_stop: e2e:long:remove
  rules:
    - if: !reference [.rules, if, main_no_schedule]

e2e:long:remove:
  extends:
    - e2e:long
    - .dismiss
  needs:
    - e2e:long
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: always
      allow_failure: true

performance:
  extends:
    - .test:complex
  variables:
    WERF_SET_TAGS_PERFORMANCE: "tags.performance=true"
  environment:
    name: performance/${CI_PIPELINE_IID}
    on_stop: performance:remove
  resource_group: performance
  rules:
    - if: !reference [.rules, if, main_no_schedule]

performance:remove:
  extends:
    - performance
    - .dismiss
  needs:
    - performance
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: always
      allow_failure: true

review:
  stage: review
  needs:
    - images:apps:build
    - image:sources:build
  variables:
    ENABLE_ALL_IMAGES: "true"
    WERF_SET_TAGS_RELEASE: "tags.release=true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf converge --save-deploy-report
  environment:
    name: review/${CI_MERGE_REQUEST_IID}
    on_stop: review:remove
    auto_stop_in: 3 days
  timeout: 30m
  interruptible: true
  resource_group: ${CI_ENVIRONMENT_SLUG}
  artifacts: !reference [.artifacts, deploy_report]
  rules:
    - if: !reference [.rules, if, mr_no_schedule]

review:remove:
  extends:
    - review
    - .dismiss
  needs:
    - review
  rules:
    - if: !reference [.rules, if, mr_no_schedule]
      when: manual
      allow_failure: true

.qa:
  stage: qa
  needs:
    - job: app1:lint
      optional: true
    - job: app2:lint
      optional: true
    - job: app1:unit
      optional: true
    - job: app2:unit
      optional: true
    - job: app1:integration
      optional: true
    - job: app2:integration
      optional: true
    - job: e2e:long
      artifacts: false
    - job: performance
      artifacts: false
  variables:
    ENABLE_ALL_IMAGES: "true"
    WERF_SET_TAGS_RELEASE: "tags.release=true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf converge --save-deploy-report
  environment:
    auto_stop_in: 3 days
  timeout: 30m
  resource_group: ${CI_ENVIRONMENT_SLUG}
  artifacts: !reference [.artifacts, deploy_report]
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual

qa:eu:
  extends:
    - .qa
  environment:
    name: qa-eu/${CI_PIPELINE_IID}
    on_stop: qa:eu:remove

qa:eu:remove:
  extends:
    - qa:eu
    - .dismiss
  needs:
    - qa:eu
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual
      allow_failure: true

qa:us:
  extends:
    - .qa
  environment:
    name: qa-us/${CI_PIPELINE_IID}
    on_stop: qa:us:remove

qa:us:remove:
  extends:
    - qa:us
    - .dismiss
  needs:
    - qa:us
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual
      allow_failure: true

.staging:shared:
  stage: staging-shared
  needs:
    - job: app1:lint
      optional: true
    - job: app2:lint
      optional: true
    - job: app1:unit
      optional: true
    - job: app2:unit
      optional: true
    - job: app1:integration
      optional: true
    - job: app2:integration
      optional: true
    - job: e2e:long
      artifacts: false
    - job: performance
      artifacts: false
  variables:
    ENABLE_ALL_IMAGES: "true"
    WERF_SET_TAGS_SHARED: "tags.shared=true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf converge
  resource_group: ${CI_ENVIRONMENT_SLUG}
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual

staging:eu:shared:
  extends:
    - .staging:shared
  environment:
    name: staging-eu/shared

staging:us:shared:
  extends:
    - .staging:shared
  environment:
    name: staging-us/shared

.staging:app:
  stage: staging-apps
  variables:
    ENABLE_ALL_IMAGES: "true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf converge

.staging:app:app1:
  extends:
    - .staging:app
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual
      changes:
        - "*"
        - ".helm/**/**"
        - "src/app1/**/**"

.staging:app:app2:
  extends:
    - .staging:app
  resource_group: ${CI_ENVIRONMENT_SLUG}
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual
      changes:
        - "*"
        - ".helm/**/**"
        - "src/app2/**/**"

staging:eu:app1:
  extends:
    - .staging:app:app1
  needs:
    - staging:eu:shared
  variables:
    WERF_SET_TAGS_APP1: "tags.app1=true"
  environment:
    name: staging-eu/app1

staging:eu:app2:
  extends:
    - .staging:app:app2
  needs:
    - staging:eu:shared
  variables:
    WERF_SET_TAGS_APP2: "tags.app2=true"
  environment:
    name: staging-eu/app2

staging:us:app1:
  extends:
    - .staging:app:app1
  needs:
    - staging:us:shared
  variables:
    WERF_SET_TAGS_APP1: "tags.app1=true"
  environment:
    name: staging-us/app1

staging:us:app2:
  extends:
    - .staging:app:app2
  needs:
    - staging:us:shared
  variables:
    WERF_SET_TAGS_APP2: "tags.app2=true"
  environment:
    name: staging-us/app2

.prod:shared:
  stage: prod-shared
  variables:
    ENABLE_ALL_IMAGES: "true"
    WERF_SET_TAGS_SHARED: "tags.shared=true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf converge
  resource_group: ${CI_ENVIRONMENT_SLUG}
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual

prod:eu:shared:
  extends:
    - .prod:shared
  needs:
    - staging:eu:smoke
  environment:
    name: prod-eu/shared

prod:us:shared:
  extends:
    - .prod:shared
  needs:
    - staging:us:smoke
  environment:
    name: prod-us/shared

.prod:app:
  stage: prod-apps
  variables:
    ENABLE_ALL_IMAGES: "true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf converge
  resource_group: ${CI_ENVIRONMENT_SLUG}

.prod:app:app1:
  extends:
    - .prod:app
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual
      changes:
        - "*"
        - ".helm/**/**"
        - "src/app1/**/**"

.prod:app:app2:
  extends:
    - .prod:app
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual
      changes:
        - "*"
        - ".helm/**/**"
        - "src/app2/**/**"

prod:eu:app1:
  extends:
    - .prod:app:app1
  needs:
    - prod:eu:shared
  variables:
    WERF_SET_TAGS_APP1: "tags.app1=true"
  environment:
    name: prod-eu/app1

prod:eu:app2:
  extends:
    - .prod:app:app2
  needs:
    - prod:eu:shared
  variables:
    WERF_SET_TAGS_APP2: "tags.app2=true"
  environment:
    name: prod-eu/app2

prod:us:app1:
  extends:
    - .prod:app:app1
  needs:
    - prod:us:shared
  variables:
    WERF_SET_TAGS_APP1: "tags.app1=true"
  environment:
    name: prod-us/app1

prod:us:app2:
  extends:
    - .prod:app:app2
  needs:
    - prod:us:shared
  variables:
    WERF_SET_TAGS_APP2: "tags.app2=true"
  environment:
    name: prod-us/app2

.smoke:
  variables:
    ENABLE_IMAGE_SOURCES: "true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf kube-run sources -- go-task test:smoke
  timeout: 20m
  rules:
    - if: !reference [.rules, if, main_no_schedule]
      when: manual

staging:eu:smoke:
  extends:
    - .smoke
  stage: staging-smoke
  needs:
    - staging:eu:shared

staging:us:smoke:
  extends:
    - .smoke
  stage: staging-smoke
  needs:
    - staging:us:shared

prod:eu:smoke:
  extends:
    - .smoke
  stage: prod-smoke
  needs:
    - prod:eu:shared

prod:us:smoke:
  extends:
    - .smoke
  stage: prod-smoke
  needs:
    - prod:us:shared

images:cleanup:
  stage: cleanup
  variables:
    ENABLE_ALL_IMAGES: "true"
  before_script:
    - !reference [.scripts, setup_werf]
  script:
    - werf cr login -u nobody -p "${WERF_IMAGES_CLEANUP_PASSWORD:?}" "${WERF_REPO:?}"
    - werf cleanup
  resource_group: cleanup-images
  rules:
    - if: !reference [.rules, if, main_schedule]

dependencies:
  - name: shared
    version: 1.0.0
    tags:
      - shared
      - apps
      - release
      - all
    export-values: &export-values
      - parent: werf
        child: werf
  - name: app
    alias: app1
    version: 1.0.0
    tags:
      - app1
      - apps
      - release
      - all
    export-values: *export-values
  - name: app
    alias: app2
    version: 1.0.0
    tags:
      - app2
      - apps
      - release
      - all
    export-values: *export-values
  - name: database
    version: 1.0.0
    condition: database.enabled
    tags:
      - database
      - infra
      - release
      - all
    export-values: *export-values
  - name: e2e-short
    version: 1.0.0
    tags:
      - e2e-short
      - tests
      - all
    export-values: *export-values
  - name: e2e-long
    version: 1.0.0
    tags:
      - e2e-long
      - tests
      - all
    export-values: *export-values
  - name: performance
    version: 1.0.0
    tags:
      - performance
      - tests
      - all
    export-values: *export-values

apiVersion: v2
name: app
version: 1.0.0

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ $.Chart.Name }}
spec:
  selector:
    matchLabels:
      app: {{ $.Chart.Name }}
  template:
    metadata:
      labels:
        app: {{ $.Chart.Name }}
    spec:
      imagePullSecrets:
        - name: registrysecret
      containers:
        - name: {{ $.Chart.Name }}
          image: {{ index $.Values.werf.image $.Chart.Name }}
          ports:
            - containerPort: 80

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ $.Chart.Name }}
spec:
  ingressClassName: nginx
  rules:
    - host: "{{ $.Release.Name }}.{{ $.Chart.Name }}.example.org"
      http:
        paths:
          - backend:
              service:
                name: {{ $.Chart.Name }}
                port:
                  number: 80
            path: /
            pathType: Prefix

{{ if $.Release.IsInstall }}
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ $.Chart.Name }}-init-db-{{ $.Release.Revision }}
  annotations:
    werf.io/weight: "-20"
spec:
  template:
    spec:
      imagePullSecrets:
        - name: registrysecret
      restartPolicy: Never
      containers:
        - name: init-db
          image: {{ $.Values.werf.image.sources }}
          command: ["go-task", "-d", "src/{{ $.Chart.Name }}", "db:init"]
{{ end }}

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ $.Chart.Name }}-migrate-db-{{ $.Release.Revision }}
  annotations:
    werf.io/weight: "-10"
spec:
  template:
    spec:
      imagePullSecrets:
        - name: registrysecret
      restartPolicy: Never
      containers:
        - name: migrate-db
          image: {{ $.Values.werf.image.sources }}
          command: ["go-task", "-d", "src/{{ $.Chart.Name }}", "db:migrate"]

apiVersion: v1
kind: Service
metadata:
  name: {{ $.Chart.Name }}
spec:
  ports:
    - port: 80
  selector:
    app: {{ $.Chart.Name }}

apiVersion: v2
name: database
version: 1.0.0

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  annotations:
    werf.io/weight: "-30"
spec:
  serviceName: db
  selector:
    matchLabels:
      app: db
  template:
    metadata:
      labels:
        app: db
    spec:
      containers:
        - name: db
          image: alpine:3.17
          command: ["tail", "-f", /dev/null]

apiVersion: v2
name: e2e-long
version: 1.0.0

apiVersion: batch/v1
kind: Job
metadata:
  name: test-e2e-long-{{ $.Release.Revision }}
  annotations:
    werf.io/weight: "10"
spec:
  template:
    spec:
      imagePullSecrets:
        - name: registrysecret
      restartPolicy: Never
      containers:
        - name: test-e2e-long
          image: {{ $.Values.werf.image.sources }}
          command: ["go-task", "test:e2e:long"]

apiVersion: v2
name: e2e-short
version: 1.0.0

apiVersion: batch/v1
kind: Job
metadata:
  name: test-e2e-short-{{ $.Release.Revision }}
  annotations:
    werf.io/weight: "10"
spec:
  template:
    spec:
      imagePullSecrets:
        - name: registrysecret
      restartPolicy: Never
      containers:
        - name: test-e2e-short
          image: {{ $.Values.werf.image.sources }}
          command: ["go-task", "test:e2e:short"]

apiVersion: v2
name: performance
version: 1.0.0

apiVersion: batch/v1
kind: Job
metadata:
  name: test-performance-{{ $.Release.Revision }}
  annotations:
    werf.io/weight: "10"
spec:
  template:
    spec:
      imagePullSecrets:
        - name: registrysecret
      restartPolicy: Never
      containers:
        - name: test-performance
          image: {{ $.Values.werf.image.sources }}
          command: ["go-task", "test:performance"]

apiVersion: v2
name: shared
version: 1.0.0

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: main
spec:
  ingressClassName: nginx
  rules:
    - host: "{{ $.Release.Name }}.example.org"
      http:
        paths:
          - backend:
              service:
                name: app1
                port:
                  number: 80
            path: /app1
            pathType: Prefix
          - backend:
              service:
                name: app2
                port:
                  number: 80
            path: /app2
            pathType: Prefix

dependencies:
- name: shared
  repository: ""
  version: 1.0.0
- name: app1
  repository: ""
  version: 1.0.0
- name: app2
  repository: ""
  version: 1.0.0
- name: database
  repository: ""
  version: 1.0.0
- name: e2e-short
  repository: ""
  version: 1.0.0
- name: e2e-long
  repository: ""
  version: 1.0.0
- name: performance
  repository: ""
  version: 1.0.0
digest: sha256:efce1b655fce8c8bf7f1739dc34a98fed3dad7943cef39bd6829aeaee34c03e9
generated: "2023-02-08T12:17:50.931015996+03:00"

{{ $chartsTagNames := dict }}
{{- range $.Chart.Dependencies }}
{{- if .Alias }}
{{- $_ := set $chartsTagNames .Alias .Tags }}
{{- else }}
{{- $_ := set $chartsTagNames .Name .Tags }}
{{- end }}
{{- end }}

{{- range $chartsTagNames.shared }}
{{- if dig . false $.Values.tags }}
Main application: https://{{ $.Release.Name }}.example.org
{{- break }}
{{- end }}
{{- end }}

{{- range $chartsTagNames.app1 }}
{{- if dig . false $.Values.tags }}
Application 1: https://{{ $.Release.Name }}.app1.example.org
{{- break }}
{{- end }}
{{- end }}

{{- range $chartsTagNames.app2 }}
{{- if dig . false $.Values.tags }}
Application 2: https://{{ $.Release.Name }}.app2.example.org
{{- break }}
{{- end }}
{{- end }}

tags:
  all: false

version: "3"

tasks:
  test:e2e:short:
    cmds:
      # Here be your short E2E tests:
      - echo Short E2E tests completed.
  test:e2e:long:
    cmds:
      # Here be your long E2E tests:
      - echo Long E2E tests completed.
  test:performance:
    cmds:
      # Here be your performance tests:
      - echo Performance tests completed.
  test:smoke:
    cmds:
      # Here be your smoke tests:
      - echo Smoke tests completed.

FROM alpine:3.17
WORKDIR /src
RUN apk add go-task
COPY . .

version: "3"

tasks:
  build:
    cmds:
      # Here be building your app:
      - cp main.sh app.sh
  run:
    cmds:
      # Here be running your app:
      - ./app.sh
  lint:
    cmds:
      # Here be your linter:
      - echo Lint completed.
  test:unit:
    cmds:
      # Here be your unit tests:
      - echo Unit tests completed. Code coverage is 12.34%
  test:integration:
    cmds:
      # Here be your integration tests:
      - echo Integration tests completed. Code coverage is 43.21%
  db:init:
    cmds:
      # Here be your DB initialization:
      - echo DB initialized.
  db:migrate:
    cmds:
      # Here be your DB migrations:
      - echo DB migrated.

FROM alpine:3.17 as builder
WORKDIR /app
RUN apk add go-task
COPY . .
RUN go-task build

FROM alpine:3.17
WORKDIR /app
RUN apk add nmap-ncat go-task
COPY --from=builder /app/app.sh /app/Taskfile.yaml ./
CMD ["go-task", "run"]

#!/bin/sh

while true; do
    printf "HTTP/1.1 200 OK\n\nHello world.\n" | ncat -lp 80
done

version: "3"

tasks:
  build:
    cmds:
      # Here be building your app:
      - cp main.sh app.sh
  run:
    cmds:
      # Here be running your app:
      - ./app.sh
  lint:
    cmds:
      # Here be your linter:
      - echo Lint completed.
  test:unit:
    cmds:
      # Here be your unit tests:
      - echo Unit tests completed. Code coverage is 12.34%
  test:integration:
    cmds:
      # Here be your integration tests:
      - echo Integration tests completed. Code coverage is 43.21%
  db:init:
    cmds:
      # Here be your DB initialization:
      - echo DB initialized.
  db:migrate:
    cmds:
      # Here be your DB migrations:
      - echo DB migrated.

FROM alpine:3.17 as builder
WORKDIR /app
RUN apk add go-task
COPY . .
RUN go-task build

FROM alpine:3.17
WORKDIR /app
RUN apk add nmap-ncat go-task
COPY --from=builder /app/app.sh /app/Taskfile.yaml ./
CMD ["go-task", "run"]

#!/bin/sh

while true; do
    printf "HTTP/1.1 200 OK\n\nHello world.\n" | ncat -lp 80
done

giterminismConfigVersion: 1
config:
  goTemplateRendering:
    allowEnvVariables:
      - ENABLE_ALL_IMAGES
      - ENABLE_APPS_IMAGES
      - ENABLE_IMAGE_SOURCES

configVersion: 1
project: myproject

{{- if or (env "ENABLE_ALL_IMAGES" | eq "true") (env "ENABLE_APPS_IMAGES" | eq "true") }}
---
image: app1
context: src/app1
dockerfile: ./app.Dockerfile

---
image: app2
context: src/app2
dockerfile: ./app.Dockerfile
{{- end }}

{{- if or (env "ENABLE_ALL_IMAGES" | eq "true") (env "ENABLE_IMAGE_SOURCES" | eq "true") }}
---
image: sources
dockerfile: ./sources.Dockerfile
{{- end }}

Extras:

  • Add authorization options for werf cleanup in the container registry by following instructions.