Commit 57154d9e authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

Merge branch 'feat/support-parallel-matrix' into 'main'

Add parallel:matrix support

See merge request to-be-continuous/s2i!23
parents a0908051 c377b900
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ The S2I template uses some global configuration used throughout all jobs.
| `skopeo-image` / `S2I_SKOPEO_IMAGE` | The container image used to run [skopeo](https://github.com/containers/skopeo) | `quay.io/containers/skopeo:latest` <br/>[![Trivy Badge](https://to-be-continuous.gitlab.io/doc/secu/trivy-badge-S2I_SKOPEO_IMAGE.svg)](https://to-be-continuous.gitlab.io/doc/secu/trivy-S2I_SKOPEO_IMAGE) |
| `version` / `S2I_VERSION` | The target S2I version to install/use      | `latest`|
| `platform` / `S2I_PLATFORM` | The target S2I platform to install/use     | `linux-386` |
| `artifacts-namespace` / `S2I_ARTIFACTS_NAMESPACE` | Output artifacts namespace _(only required when deploying [multiple environments](#multiple-environments-support))_ | _none_ |

### Images

@@ -111,6 +112,35 @@ If you use **different registries** for snapshot and release images, you shall u
| :lock: `S2I_REGISTRY_RELEASE_USER`    | container registry username for release image registry |
| :lock: `S2I_REGISTRY_RELEASE_PASSWORD`| container registry password for release image registry |

### Multiple images build

The S2I template allows building multiple images in parallel (for instance with multiple separate application source code base directories in your repository).

This feature can be enabled using the [parallel matrix jobs](https://docs.gitlab.com/ee/ci/yaml/#parallelmatrix)
pattern at the `.s2i-base` job level. 
Output variables namespacing can be ensured by using the `S2I_ARTIFACTS_NAMESPACE` variable.

Here is the example of the `.gitlab-ci.yml` file for a project building 2 application images:

```yaml
.s2i-base:
  parallel:
    matrix:
      - S2I_ARTIFACTS_NAMESPACE: "app1"
        S2I_ROOT_DIR: "src/app1"
        S2I_SNAPSHOT_IMAGE: "$CI_REGISTRY_IMAGE/app1/snapshot:$CI_COMMIT_REF_SLUG"
        S2I_RELEASE_IMAGE: "$CI_REGISTRY_IMAGE/app1:$CI_COMMIT_REF_NAME"
      - S2I_ARTIFACTS_NAMESPACE: "app2"
        S2I_ROOT_DIR: "src/app2"
        S2I_SNAPSHOT_IMAGE: "$CI_REGISTRY_IMAGE/app2/snapshot:$CI_COMMIT_REF_SLUG"
        S2I_RELEASE_IMAGE: "$CI_REGISTRY_IMAGE/app2:$CI_COMMIT_REF_NAME"
```

The above configuration will instantiate the S2I pipeline twice, one for each application with all required jobs.

> [!tip]
> Setting the `S2I_ARTIFACTS_NAMESPACE` variable is only necessary if you need to namespace the build job output variables.

### Secrets management

Here are some advices about your **secrets** (variables marked with a :lock:):
@@ -153,6 +183,16 @@ This job produces _output variables_ that are propagated to downstream jobs (usi

They may be freely used in downstream jobs (for instance to deploy the upstream built image, whatever the branch or tag).

> [!important]
> If [multiple images build](#multiple-images-build) is configured and `S2I_ARTIFACTS_NAMESPACE` is set, the output variables are namespaced with a 
> sluggified value of the `S2I_ARTIFACTS_NAMESPACE` variable (stripped of punctuation characters and converted to lowercase):
> 
> * `s2i_<namespace_slug>_image`: snapshot image name **with tag**,
> * `s2i_<namespace_slug>_image_digest`: snapshot image name **with digest** (no tag),
> * `s2i_<namespace_slug>_repository`: snapshot image **bare repository** (no tag nor digest),
> * `s2i_<namespace_slug>_tag`: snapshot image tag,
> * `s2i_<namespace_slug>_digest`: snapshot image digest.

### `s2i-trivy` job

This job performs a Vulnerability Static Analysis with [Trivy](https://trivy.dev) on your built image.
@@ -216,6 +256,16 @@ This job produces _output variables_ that are propagated to downstream jobs (usi

They may be freely used in downstream jobs (for instance to deploy the upstream built image, whatever the branch or tag).

> [!important]
> If [multiple images build](#multiple-images-build) is configured and `S2I_ARTIFACTS_NAMESPACE` is set, the output variables are namespaced with a 
> sluggified value of the `S2I_ARTIFACTS_NAMESPACE` variable (stripped of punctuation characters and converted to lowercase):
> 
> * `s2i_<namespace_slug>_image`: release image name **with tag**,
> * `s2i_<namespace_slug>_image_digest`: release image name **with digest** (no tag),
> * `s2i_<namespace_slug>_repository`: release image **bare repository** (no tag nor digest),
> * `s2i_<namespace_slug>_tag`: release image tag,
> * `s2i_<namespace_slug>_digest`: release image digest.

#### Using extra tags

When publishing the _release_ image, the S2I template might publish it again with additional tags (aliases):
+5 −0
Original line number Diff line number Diff line
@@ -81,6 +81,11 @@
      "name": "S2I_SEMREL_RELEASE_DISABLED",
      "description": "Disable integration with the [semantic release template](https://gitlab.com/to-be-continuous/semantic-release/)",
      "type": "boolean"
    },
    {
      "name": "S2I_ARTIFACTS_NAMESPACE",
      "description": "Output artifacts namespace _(only required when building multiple images)_",
      "advanced": true
    }
  ],
  "features": [
+27 −23
Original line number Diff line number Diff line
@@ -43,6 +43,9 @@ spec:
    release-image:
      description: S2I release image
      default: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
    artifacts-namespace:
      description: Output artifacts namespace _(only required when building multiple images)_
      default: ''
    trivy-disabled:
      description: Disable Trivy
      type: boolean
@@ -154,6 +157,7 @@ variables:

  # Relative path to the application source code base directory in your repository
  S2I_ROOT_DIR: $[[ inputs.root-dir ]]
  S2I_ARTIFACTS_NAMESPACE: $[[ inputs.artifacts-namespace ]]

  # Trivy configuration
  S2I_TRIVY_IMAGE: $[[ inputs.trivy-image ]]
@@ -487,6 +491,25 @@ stages:
    touch "$CI_PROJECT_DIR/.cache/s2i-$S2I_VERSION-$S2I_PLATFORM.txt"
  }

  function create_dotenv_file() {
    s2i_digest=$1
    s2i_image=${2:-$S2I_SNAPSHOT_IMAGE}

    s2i_repository=${s2i_image%:*}
    s2i_tag=${s2i_image##*:}
    ans_slug=$(echo "$S2I_ARTIFACTS_NAMESPACE" | tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]')
    var_prefix="${ans_slug:+${ans_slug}_}"
    dotenvfile="s2i.env${ans_slug:+.${ans_slug}}"
    {
      echo "s2i_${var_prefix}image=$s2i_image"
      echo "s2i_${var_prefix}image_digest=$s2i_repository@$s2i_digest"
      echo "s2i_${var_prefix}repository=$s2i_repository"
      echo "s2i_${var_prefix}tag=$s2i_tag"
      echo "s2i_${var_prefix}digest=$s2i_digest"
    } > "$dotenvfile"
    chmod 644 "$dotenvfile"
  }

  function publish_extra_tags() {
    if [[ -z "$S2I_RELEASE_EXTRA_TAGS" ]]
    then
@@ -553,7 +576,6 @@ s2i-build:
    - maybe_install_s2i
    # exploded image info
    - s2i_repository=${S2I_SNAPSHOT_IMAGE%:*}
    - s2i_tag=${S2I_SNAPSHOT_IMAGE##*:}
    - s2i_image_path=${s2i_repository#*/}
    # build image (see: https://github.com/openshift/source-to-image/blob/master/docs/cli.md#s2i-build)
    - '"$CI_PROJECT_DIR/.cache/s2i" build --url="tcp://docker:2375" "$S2I_ROOT_DIR" "$S2I_BUILDER_IMAGE" "$s2i_image_path" ${S2I_BUILD_EXTRA_FLAGS}'
@@ -562,19 +584,11 @@ s2i-build:
    # eval image digest
    - s2i_digest=$(skopeo inspect --authfile ~/.docker/config.json --format='{{ .Digest }}' "docker://$S2I_SNAPSHOT_IMAGE")
    # create output dotenv file
    - |
      {
        echo "s2i_image=$S2I_SNAPSHOT_IMAGE"
        echo "s2i_image_digest=$s2i_repository@$s2i_digest"
        echo "s2i_repository=$s2i_repository"
        echo "s2i_tag=$s2i_tag"
        echo "s2i_digest=$s2i_digest"
      } > s2i.env
      chmod 644 s2i.env
    - create_dotenv_file "$s2i_digest"
  artifacts:
    reports:
      dotenv:
        - s2i.env
        - s2i.env*

# Security audit with trivy
s2i-trivy:
@@ -663,23 +677,13 @@ s2i-publish:
    - 'skopeo copy --src-authfile ~/.docker/config.json --dest-authfile ~/.docker/release-config.json ${S2I_PUBLISH_ARGS} docker://$S2I_SNAPSHOT_IMAGE docker://$S2I_RELEASE_IMAGE'
    - 'log_info "Well done your image is published and can be downloaded by doing: docker pull $S2I_RELEASE_IMAGE"'
    # build output dotenv
    - s2i_repository=${S2I_RELEASE_IMAGE%:*}
    - s2i_tag=${S2I_RELEASE_IMAGE##*:}
    - s2i_digest=$(skopeo inspect --authfile ~/.docker/release-config.json --format='{{ .Digest }}' "docker://$S2I_RELEASE_IMAGE")
    - |
      {
        echo "s2i_image=$S2I_RELEASE_IMAGE"
        echo "s2i_image_digest=$s2i_repository@$s2i_digest"
        echo "s2i_repository=$s2i_repository"
        echo "s2i_tag=$s2i_tag"
        echo "s2i_digest=$s2i_digest"
      } > s2i.env
      chmod 644 s2i.env
    - create_dotenv_file "$s2i_digest" "$S2I_RELEASE_IMAGE"
    - publish_extra_tags
  artifacts:
    reports:
      dotenv:
        - s2i.env
        - s2i.env*
  rules:
    # on tag: if semrel info not enabled or semrel integration disabled
    - if: '$CI_COMMIT_TAG && ($SEMREL_INFO_ON == null || $SEMREL_INFO_ON == "" || $S2I_SEMREL_RELEASE_DISABLED == "true")'