Erstellen wiederverwendbarer Pipelines für GitLab CI in Bash

In den letzten Jahren habe ich GitLab CI sehr gemocht . Hauptsächlich wegen seiner Einfachheit und Funktionalität. Es reicht aus, nur eine Datei im Stammverzeichnis des Repositorys zu erstellen .gitlab-ci.yml



, dort einige Codezeilen hinzuzufügen , und beim nächsten Festschreiben wird die Pipeline mit einer Reihe von Jobs gestartet, die die angegebenen Befehle ausführen.





Und wenn Sie das Add umfassen und erweitern Fähigkeiten dazu , können Sie ganz interessante Dinge tun: template Arbeitsplätze und Pipelines erstellen, sie in separate Repositorys bewegen und sie in verschiedenen Projekten wieder verwenden , ohne den Code zu kopieren.





Aber leider ist nicht alles so rosig, wie wir es gerne hätten. Die Anweisung script



in GitLab CI ist sehr niedrig. Es führt einfach die Befehle aus, die ihm in Form von Zeichenfolgen gegeben werden. Es ist nicht sehr bequem, große Skripte in YAML zu schreiben. Wenn die Logik komplexer wird, die Anzahl der Skripte zunimmt, mischen sie sich mit YAML, wodurch Konfigurationen unlesbar werden und ihre Wartung kompliziert wird.





Ich habe wirklich einen Mechanismus vermisst, der die Entwicklung großer Skripte vereinfachen würde. Als Ergebnis wurde ein Mikroframework für die Entwicklung von GitLab CI geboren, über das ich in diesem Artikel sprechen möchte (am Beispiel einer einfachen Pipeline zum Erstellen von Docker-Images).





Beispiel: Erstellen von Docker-Images in GitLab

Ich möchte den Prozess des Erstellens einer Pipeline anhand eines Beispiels für eine einfache Aufgabe betrachten, die ich häufig mit verschiedenen Teams getroffen habe: Erstellen grundlegender Docker-Images in GitLab zur Wiederverwendung.





Beispielsweise schreibt ein Team Microservices und möchte für alle ein eigenes Basis-Image mit einer Reihe vorinstallierter Debugging-Dienstprogramme verwenden.





In einem anderen Beispiel schreibt ein Team Tests und möchte Dienste direkt in GitLab verwenden, um mithilfe ihres eigenen Images eine temporäre Datenbank (oder Warteschlange oder etwas anderes) für sie zu erstellen.





, docker- GitLab . .gitlab-ci.yml



:





services:
  - docker:dind

Build:
  image: docker
  script:
    - |
      docker login "$CI_REGISTRY" \
        --username "$CI_REGISTRY_USER" \
        --password "$CI_REGISTRY_PASSWORD"

      docker build \
        --file "Dockerfile" \
        --tag "$CI_REGISTRY/$CI_PROJECT_PATH:$CI_COMMIT_REF_SLUG" .

      docker push "$CI_REGISTRY/$CI_PROJECT_PATH:$CI_COMMIT_REF_SLUG"
      
      



Build



, GitLab Container Registry, . , ( , ).





, , :





  • , dockerfiles



    .





  • :





    • Build All



      - dockerfiles



      . ( ).





    • Build Changed



      - dockerfiles



      , . ( ) .





. . , .





:









, .NET.





:









docker-, Container Registry :





, .





1: " "

. .gitlab-ci.yml



. :





services:
  - docker:dind

stages:
  - Build

Build All:
  stage: Build
  image: docker
  when: manual
  script:
    - |
      dockerfiles=$(find "dockerfiles" -name "*.Dockerfile" -type f)

      docker login "$CI_REGISTRY" \
        --username "$CI_REGISTRY_USER" \
        --password "$CI_REGISTRY_PASSWORD"

      for dockerfile in $dockerfiles; do
        path=$(echo "$dockerfile" | sed 's/^dockerfiles\///' | sed 's/\.Dockerfile$//')
        tag="$CI_REGISTRY/$CI_PROJECT_PATH/$path:$CI_COMMIT_REF_SLUG"

        echo "Building $dockerfile..."
        docker build --file "$dockerfile" --tag "$tag" .

        echo "Pushing $tag..."
        docker push "$tag"
      done

Build Changed:
  stage: Build
  image: docker
  only:
    changes:
      - 'dockerfiles/*.Dockerfile'
      - 'dockerfiles/**/*.Dockerfile'
  script:
    - |
      apk update
      apk add git #  ,     ,    ...

      dockerfiles=$(git diff --name-only HEAD HEAD~1 -- 'dockerfiles/***.Dockerfile')

      docker login "$CI_REGISTRY" \
        --username "$CI_REGISTRY_USER" \
        --password "$CI_REGISTRY_PASSWORD"

      for dockerfile in $dockerfiles; do
        path=$(echo "$dockerfile" | sed 's/^dockerfiles\///' | sed 's/\.Dockerfile$//')
        tag="$CI_REGISTRY/$CI_PROJECT_PATH/$path:$CI_COMMIT_REF_SLUG"

        echo "Building $dockerfile..."
        docker build --file "$dockerfile" --tag "$tag" .

        echo "Pushing $tag..."
        docker push "$tag"
      done
      
      



:





  • ( step1)









:





  • Build All



    , :





    • , .. when: manual



      .





    • :





      • find "dockerfiles" -name "*.Dockerfile" -type f







  • Build Changed



    , :





    • , .. only:changes



      .





    • , :





      • git diff --name-only HEAD HEAD~1 -- 'dockerfiles/***.Dockerfile'







  • , , , dockerfiles/



    .Dockerfile



    , GitLab Container Registry.





:





  • ( )





  • , .





GitLab CI .





GitLab CI Bootstrap

GitLab CI Bootstrap - GitLab CI. :





  • ( .gitlab-ci.yml



    ) (bash shell), YAML .





  • , .





  • ( ) , .





GitLab CI Bootstrap bootstrap.gitlab-ci.yml, .gitlab-ci.yml



include. . include:local:





include:
  - local: 'bootstrap.gitlab-ci.yml'
      
      



.bootstrap



, :





.bootstrap:
  before_script:
    - |
     	...
      
      



.bootstrap



, extends:





example:
  extends: '.bootstrap'
  script:
    - '...'
      
      



( ), GitLab.





. . , , .





bash shell. git, . .bootstrap



docker- .





, , docker-.





2:

, .bootstrap



.gitlab-ci.sh



. , .





, , .gitlab-ci.yml



:





.gitlab-ci.yml



:





include:
  - project: '$CI_PROJECT_NAMESPACE/bootstrap'
    ref: 'master'
    file: 'bootstrap.gitlab-ci.yml'

services:
  - docker:dind

stages:
  - Build

Build All:
  stage: Build
  image: docker
  extends: .bootstrap
  when: manual
  script:
    - search_all_dockerfiles_task
    - build_and_push_dockerfiles_task

Build Changed:
  stage: Build
  image: docker
  extends: .bootstrap
  only:
    changes:
      - 'dockerfiles/*.Dockerfile'
      - 'dockerfiles/**/*.Dockerfile'
  script:
    - install_git_task
    - search_changed_dockerfiles_task
    - build_and_push_dockerfiles_task
      
      



.gitlab-ci.sh



:





DOCKERFILES=""

function search_all_dockerfiles_task() {
    DOCKERFILES=$(find "dockerfiles" -name "*.Dockerfile" -type f)
}

function search_changed_dockerfiles_task() {
    DOCKERFILES=$(git diff --name-only HEAD HEAD~1 -- 'dockerfiles/***.Dockerfile')
}

function install_git_task() {
    #  ,     ,    ...
    apk update
    apk add git
}

function build_and_push_dockerfiles_task() {
    docker login "$CI_REGISTRY" \
        --username "$CI_REGISTRY_USER" \
        --password "$CI_REGISTRY_PASSWORD"

    for dockerfile in $DOCKERFILES; do
        path=$(echo "$dockerfile" | sed 's/^dockerfiles\///' | sed 's/\.Dockerfile$//')
        tag="$CI_REGISTRY/$CI_PROJECT_PATH/$path:$CI_COMMIT_REF_SLUG"

        echo "Building $dockerfile..."
        docker build --file "$dockerfile" --tag "$tag" .

        echo "Pushing $tag..."
        docker push "$tag"
    done
}
      
      



:





gitlab-ci.sh



, .gitlab-ci.yml



. search_all_dockerfiles_task



search_changed_dockerfiles_task



DOCKERFILES



, build_and_push_dockerfiles_task



.





3:

, , . , , . , - , , .





include.





. , , , - , . , .





, .bootstrap



CI_IMPORT



, : CI_{module}_PROJECT



, CI_{module}_REF



CI_{module}_FILE



, {module}



- CI_IMPORT



( ).





, .gitlab-ci.sh



, .





:





.gitlab-ci.yml



:





include:
  - project: '$CI_PROJECT_NAMESPACE/dockerfiles-example-ci'
    ref: 'step3'
    file: 'dockerfiles.gitlab-ci.yml'
      
      



:





dockerfiles.gitlab-ci.yml



( .gitlab-ci.yml



):





include:
  - project: '$CI_PROJECT_NAMESPACE/bootstrap'
    ref: 'master'
    file: 'bootstrap.gitlab-ci.yml'

services:
  - docker:dind

stages:
  - Build

variables:
  CI_DOCKERFILES_PROJECT: '$CI_PROJECT_NAMESPACE/dockerfiles-example-ci'
  CI_DOCKERFILES_REF: 'step3'
  CI_DOCKERFILES_FILE: 'dockerfiles.gitlab-ci.sh'

Build All:
  stage: Build
  image: docker
  extends: .bootstrap
  variables:
    CI_IMPORT: dockerfiles
  when: manual
  script:
    - search_all_dockerfiles_task
    - build_and_push_dockerfiles_task

Build Changed:
  stage: Build
  image: docker
  extends: .bootstrap
  variables:
    CI_IMPORT: dockerfiles
  only:
    changes:
      - 'dockerfiles/*.Dockerfile'
      - 'dockerfiles/**/*.Dockerfile'
  script:
    - search_changed_dockerfiles_task
    - build_and_push_dockerfiles_task
      
      



dockerfiles.gitlab-ci.sh



( .gitlab-ci.sh



):





DOCKERFILES=""

function search_all_dockerfiles_task() {
    DOCKERFILES=$(find "dockerfiles" -name "*.Dockerfile" -type f)
}

function search_changed_dockerfiles_task() {
    DOCKERFILES=$(git diff --name-only HEAD HEAD~1 -- 'dockerfiles/***.Dockerfile')
}

function build_and_push_dockerfiles_task() {
    docker login "$CI_REGISTRY" \
        --username "$CI_REGISTRY_USER" \
        --password "$CI_REGISTRY_PASSWORD"

    for dockerfile in $DOCKERFILES; do
        path=$(echo "$dockerfile" | sed 's/^dockerfiles\///' | sed 's/\.Dockerfile$//')
        tag="$CI_REGISTRY/$CI_PROJECT_PATH/$path:$CI_COMMIT_REF_SLUG"

        echo "Building $dockerfile..."
        docker build --file "$dockerfile" --tag "$tag" .

        echo "Pushing $tag..."
        docker push "$tag"
    done
}
      
      



:





Build All



Build Changed



CI_IMPORT



dockerfiles



. : CI_DOCKERFILES_PROJECT



, CI_DOCKERFILES_REF



CI_DOCKERFILES_FILE



, .





, dockerfiles.gitlab-ci.sh



, $CI_PROJECT_NAMESPACE/dockerfiles-example-ci



, step3



.





, install_git_task



. git , .. git git .





4:

. , .





dockerfiles.gitlab-ci.sh



. , .





, include



, , . , . include



, .





, , include



.





dockerfiles.gitlab-ci.sh



:





dockerfiles.gitlab-ci.sh



:





include "tasks/search.sh"
include "tasks/docker.sh"
      
      



tasks/search.sh



:





DOCKERFILES=""

function search_all_dockerfiles_task() {
    DOCKERFILES=$(find "dockerfiles" -name "*.Dockerfile" -type f)
}

function search_changed_dockerfiles_task() {
    DOCKERFILES=$(git diff --name-only HEAD HEAD~1 -- 'dockerfiles/***.Dockerfile')
}
      
      



tasks/docker.sh



:





function build_and_push_dockerfiles_task() {
    docker login "$CI_REGISTRY" \
        --username "$CI_REGISTRY_USER" \
        --password "$CI_REGISTRY_PASSWORD"

    for dockerfile in $DOCKERFILES; do
        path=$(echo "$dockerfile" | sed 's/^dockerfiles\///' | sed 's/\.Dockerfile$//')
        tag="$CI_REGISTRY/$CI_PROJECT_PATH/$path:$CI_COMMIT_REF_SLUG"

        echo "Building $dockerfile..."
        docker build --file "$dockerfile" --tag "$tag" .

        echo "Pushing $tag..."
        docker push "$tag"
    done
}
      
      



:





GitLab CI bash GitLab CI Bootstrap.





. :





  • . .. , . GitLab CI.





  • . , Python C#.





  • . , .





, .





, 1.0. , . , .





Quellen: finden Sie hier: https://gitlab.com/chakrygin/bootstrap





Repositories mit Beispielen hier:








All Articles