WoJ
WoJ

Reputation: 30035

How to conditionally update a CI/CD job image?

I just got into the (wonderful) world of CI/CD and have working pipelines. They are not optimal, though.

The application is a dockerized website:

My current setup is quite naïve (I added some comments to show why I believe the various elements are needed/useful):

# I start with a small image
image: alpine

# before the job I need to have npm and docker
# the problem: I need one in one job, and the second one in the other
# I do not need both on both jobs but do not see how to split them
before_script:
    - apk add --update npm
    - apk add docker
    - npm install
    - npm install webpack -g

stages:
    - create_dist
    - build_container
    - stop_container
    - deploy_container

# the dist directory is preserved for the other job which will make use of it
create_dist:
    stage: create_dist
    script: npm run build
    artifacts:
        paths:
        - dist

# the following three jobs are remote and need to be daisy chained
build_container:
    stage: build_container
    script: docker -H tcp://eu13:51515 build -t widgets-sentinels .

stop_container:
    stage: stop_container
    script: docker -H tcp://eu13:51515 stop widgets-sentinels
    allow_failure: true

deploy_container:
    stage: deploy_container
    script: docker -H tcp://eu13:51515 run --rm -p 8880:8888 --name widgets-sentinels -d widgets-sentinels

This setups works bit npm and docker are installed in both jobs. This is not needed and slows down the deployment. Is there a way to state that such and such packages need to be added for specific jobs (and not globally to all of them)?

To make it clear: this is not a show stopper (and in reality not likely to be an issue at all) but I fear that my approach to such a job automation is incorrect.

Upvotes: 1

Views: 572

Answers (3)

Anna Slastnikova
Anna Slastnikova

Reputation: 1558

As well as referncing different images for different jobs you may also try gitlab anchors which provides reusable templates for the jobs:

.install-npm-template: &npm-template
  before_script:
  - apk add --update npm
  - npm install
  - npm install webpack -g

.install-docker-template: &docker-template
  before_script:
  - apk add docker

create_dist:
    <<: *npm-template
    stage: create_dist
    script: npm run build
...

deploy_container:
    <<: *docker-template
    stage: deploy_container
...

Upvotes: 1

rflume
rflume

Reputation: 919

You don't necessarily need to use the same image for all jobs. Let me show you one of our pipelines (partially) which does a similar thing, just with composer for php instead of npm:

cache:
  paths:
    - vendor/

build:composer:
  image: registry.example.com/base-images/php-composer:latest # use our custom base image where only composer is installed on to build the dependencies)
  stage: build dependencies
  script:
    - php composer.phar install --no-scripts
  artifacts:
    paths:
      - vendor/
  only:
    changes:
      - composer.{json,lock,phar}  # build vendor folder only, when relevant files change, otherwise use cached folder form s3 bucket (configured in runner config)

build:api:
  image: docker:18  # use docker image to build the actual application image
  stage: build api
  dependencies:
    - build:composer # reference dependency dir
  script:
    - docker login -u gitlab-ci-token -p "$CI_BUILD_TOKEN" "$CI_REGISTRY"
    - docker build -t $CI_REGISTRY_IMAGE:latest.
    - docker push $CI_REGISTRY_IMAGE:latest

The composer base image contains all necessary packages to run composer, so in your case you'd create a base image for npm:

FROM alpine:latest 

RUN apk add --update npm

Then, use this image in your create_dist stage and use image: docker:latest as image in the other stages.

Upvotes: 1

Akash Sharma
Akash Sharma

Reputation: 757

Try multistage builder, you can intermediate temporary images and copy generated content final docker image. Also, npm should be part on docker image, create one npm image and use in final docker image as builder image.

Upvotes: 0

Related Questions