next.jsgitlabgitlab-cigitlab-autodevops

Building different images for each environment with Gitlab-CI AutoDevOps


Dockerfiles accept ENV variables via --build-args. These vars are mandatory for NextJS, used for static pages (to call remote APIs) and are "Hard coded" within the built image.

Gitlab-CI AutoDevOps has an ENV var to pass these args (AUTO_DEVOPS_BUILD_IMAGE_EXTRA_ARGS). But this is only consumeable if you are using one environment/image. When multiple environments (staging and production) needed, the URLs differ (https://staging.exmpl.com and https://www.exmpl.com).

How do I have to modify the Gitlab AutoDevOps to have two different images built?

In the CI/CD Settings my AUTO_DEVOPS_BUILD_IMAGE_EXTRA_ARGS are set:

--build-arg=API_URL=https://staging.exmpl.at/backend --build-arg=NEXT_PUBLIC_API_URL=https://staging.exmpl.at/backend
# as well $NEXT_PUBLIC_API_URL is set there

Currently this is my complete gitlab-ci.yml:

include:
  - template: Auto-DevOps.gitlab-ci.yml

# added vars for build
build:
  stage: build
  variables:
    API_URL: $NEXT_PUBLIC_API_URL
    NEXT_PUBLIC_API_URL: $NEXT_PUBLIC_API_URL

How can I build two images, without "leaving" AutoDevOps? I assume I have to customize the build stage.

Another idea is to create a second Git repository called production with production URL set for $NEXT_PUBLIC_API_URL:

Then I have two images.

Has someone please a better idea?

Thank you in advance


Solution

  • Maybe a couple way you can do this. It's pretty easy if you only care about the build job.

    One way would be to make a second job which extends: from build

    build:
      variables:
        MY_ENV: staging
    
    build production:
      extends: build
      variables:
        MY_ENV: production
    

    Another way might be to add a parallel:matrix: key to the build job

    build:
      parallel:
        matrix:
          - MY_ENV: staging
          - MY_ENV: production
    

    Keep in mind, however, if any jobs downstream of build depends on its artifacts, you'll need to manage those as well.

    For example:

    build:
      variables:
        MY_ENV: staging
    
    build production:
      extends: build
      variables:
        MY_ENV: production
    
    # some other job inherited from a template that depends on `build`
    # we also want two of these jobs for each environment
    downstream:
      variables:
        MY_ENV: staging
    
    # extend it for production
    downstream production:
      extends: downstream
      dependencies:  # make sure we get artifacts from correct upstream build job
        - build production
      variables:
        MY_ENV: production