Using YAML aliases to DRY your configurations

yaml-ar21.png

When projects reach any level of complexity the ability to change the projects configuration arises. Often YAML is used as a human and machine readable syntax to store configuration. Kubernetes, Java Spring Boot, GitLab, Docker, Ansible, AWS CloudFormation, and many other projects use YAML. YAML is a corner stone syntax in modern applications.

Understanding that YAML supports aliases can go a long way towards reducing repeated configuration. Lets take a look at a GitLab pipeline that is not using aliases.

include:
  - project: devops/pipelines/gitlab-ci
    file: qa-checkov.yml
  - project: devops/pipelines/gitlab-ci
    file: qa-conftest.yml

image:
  name: us.gcr.io/my-org/container-name:1.2.3

cache:
  paths:
    - .helm
    - .terraform
    - /root
    - ~/.ssh

stages:
  - config
  - init
  - qa
  - plan
  - apply
  - commit

terraform:
  except:
    - pipelines
  script:
    - echo "Configuration started..."
    - git config --global user.email "terradrone@tenerum.io"
    - git config --global user.name "terradrone"
    - eval $(ssh-agent -s)
    - echo "$DEPLOY_SSH" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts && chmod 644 ~/.ssh/known_hosts
    - echo "Configuration completed..."
    - terraform init
  stage: init

terraform-plan:
  artifacts:
    paths:
      - planfile-$CI_COMMIT_REF_NAME
  except:
    - pipelines
  script:
    - echo "Configuration started..."
    - git config --global user.email "terradrone@tenerum.io"
    - git config --global user.name "terradrone"
    - eval $(ssh-agent -s)
    - echo "$DEPLOY_SSH" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts && chmod 644 ~/.ssh/known_hosts
    - echo "Configuration completed..."
    - HOST="" terraform plan -out "planfile-$CI_COMMIT_REF_NAME"
  stage: plan

terraform-apply:
  except:
    - pipelines
  only:
    - master
  script:
    - echo "Configuration started..."
    - git config --global user.email "terradrone@tenerum.io"
    - git config --global user.name "terradrone"
    - eval $(ssh-agent -s)
    - echo "$DEPLOY_SSH" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts && chmod 644 ~/.ssh/known_hosts
    - echo "Configuration completed..."
    - HOST="" terraform apply "planfile-$CI_COMMIT_REF_NAME"
  stage: apply

tag:
  only:
    - pipelines
  script:
    - echo "Configuration started..."
    - git config --global user.email "terradrone@tenerum.io"
    - git config --global user.name "terradrone"
    - eval $(ssh-agent -s)
    - echo "$DEPLOY_SSH" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts && chmod 644 ~/.ssh/known_hosts
    - echo "Configuration completed..."
    - eval $(ssh-agent -s) && ssh-add <(terraform output ssh-key)
    - git clone git@${CI_SERVER_HOST}:${CI_PROJECT_PATH}.git
  stage: apply

commit:
  except:
    - tags
    - pipelines
  only:
    - master
  script:
    - echo "Configuration started..."
    - git config --global user.email "terradrone@tenerum.io"
    - git config --global user.name "terradrone"
    - eval $(ssh-agent -s)
    - echo "$DEPLOY_SSH" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts && chmod 644 ~/.ssh/known_hosts
    - echo "Configuration completed..."
    - eval $(ssh-agent -s) && ssh-add <(terraform output ssh-key)
    - cd ${CI_PROJECT_NAME}
    - git checkout ${CI_COMMIT_REF_NAME}
  stage: commit

Look at all that repeated configuration code. This pipeline would me a pain to manage.

Now lets take a look at the same pipeline with YAML alias pattern applied.

include:
  - project: devops/pipelines/gitlab-ci
    file: qa-checkov.yml
  - project: devops/pipelines/gitlab-ci
    file: qa-conftest.yml

image:
  name: us.gcr.io/my-org/container-name:1.2.3

cache:
  paths:
    - .helm
    - .terraform
    - /root
    - ~/.ssh

stages:
  - config
  - init
  - qa
  - plan
  - apply
  - commit

# This is the anchor of the alias, the definition
.config: &config
- echo "Configuration started..."
- git config --global user.email "terradrone@tenerum.io"
- git config --global user.name "terradrone"
- eval $(ssh-agent -s)
- echo "$DEPLOY_SSH" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts && chmod 644 ~/.ssh/known_hosts
- eval $(ssh-agent -s) && ssh-add <(terraform output ssh-key)
- echo "Configuration completed..."

terraform:
  except:
    - pipelines
  script:
    # this is a YAML reference to the anchor defined above
    - *config
    - terraform init
  stage: init

terraform-plan:
  artifacts:
    paths:
      - planfile-$CI_COMMIT_REF_NAME
  except:
    - pipelines
  script:
    - *config
    - HOST="" terraform plan -out "planfile-$CI_COMMIT_REF_NAME"
  stage: plan

terraform-apply:
  except:
    - pipelines
  only:
    - master
  script:
    - *config
    - HOST="" terraform apply "planfile-$CI_COMMIT_REF_NAME"
  stage: apply

tag:
  only:
    - pipelines
  script:
    - *config
    - git clone git@${CI_SERVER_HOST}:${CI_PROJECT_PATH}.git
  stage: apply

commit:
  except:
    - tags
    - pipelines
  only:
    - master
  script:
    - *config
    - cd ${CI_PROJECT_NAME}
    - git checkout ${CI_COMMIT_REF_NAME}
  stage: commit

That looks so much better, much more pragmatic, and much easier to maintain.

Conclusion

Using YAML alias we are now able to reduce complexity, increase maintainability, and DRY yaml configurations.

Additional References

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.