gitlab tips

### Services: コンテナイメージを複数扱う
servicesというキーワードを用いると、ベースイメージと接続可能なコンテナを定義できる

servies:
  - postgres:latest
variables:
  POSTGRES_DB: custom_db
  POSTGRES_USER: ucstom_user
  POSTGRES_PASSWORD: custom_password

### Anchors

test1:
  stage: test
  image: python:latest
  before_script:
    - pipenv install --dev --system
  script:
    - pytest test1

test2:
  state: test
  image: python:latest
  before_script:
    - pipenv install --dev --system
  script:
    - pytest test2
.test_template: &test_definition
  state: test
  image: python:latest
  before_script:
    - pipenv install --dev --system

test1:
  <<: *test_definition
  script:
    - pytest test1

test2:
  <<: *test_definition
  script:
    - pytest test2  

### 用意されているGitlab変数

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
  script:
    - docker build --pull -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
  only:
    - tags

### only and except
tagがpushされた時のみ
only:
– tags
ブランチがpushされた時は実行しない
except:
– master

あれ、Dockerfileではなく、gitlab.ymlにimageを書くの?

gitlab-ci.yml練習

stages:
  - prepare
  - echo

prepare-job:
  stage: prepare
  script:
    - echo "Prepare bofore echo"

echo-job:
  stage: echo
  script: 
    - echo "Ahoy! This is Gitlab CI/CD!"

stages:
  - dev
  - stg

dev-job:
  stage: dev
  script:
    - echo "Hello, $GITLAB_USER_LOGIN!"
    - echo "This is $CI_COMMIT_BRANCH branch."
    - sleep 5

stg-job:
  stage: stg
  script:
    - echo "hello world!"

$GITLAB_USER_LOGIN, $CI_COMMIT_BRANCH branchは予め用意されている模様

### Docker

default:
  image: ruby:2.7.2

stages:
  - stg

hello-job:
  stage: stg
  script:
    - ruby -v

### artifact

stages:
  - dev

generate-file:
  stage: dev
  artifacts:
    paths:
      - hoge.txt
  script:
    - echo hoge > hoge.txt

なるほど、なんか色々できそうなことはわかった

GitLab Container Registryを使おう

registoryにログインします
$ sudo docker login registry.gitlab.com
Login Succeeded

Dockerfile

FROM alpine:latest

### build
$ sudo docker build -t registry.gitlab.com/hpscript/docker .
$ sudo docker images;
registry.gitlab.com/hpscript/docker latest 9c842ac49a39 41 hours ago 5.57MB
$ sudo docker push registry.gitlab.com/hpscript/docker

なるほどー、なんか勉強になるな

[GitLab] GitLab Container Registryによるコンテナイメージの管理

Docker HubやGoogle container Registryと同様に、GitLabにもGitLab Container Registryが備わっている。

$ docker login registry.gitlab.com
$ docker build -t registry.gitlab.com/hoge/myproject .
$ docker push registry.gitlab.com/hoge/myproject

コンテナイメージの名前を変数化

job01:
  stages:
    - build
    - test
    - deploy

  variables:
    CONTAINER_NAME: ${CI_PROJECT_NAME}_${APP_NAME}
    CONTAINER_IMAGE: ${CI_REGISTRY}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}/${APP_NAME}

  packaged_web_app:
    stage: packaged
    before_script:
      - docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
    script:
      - cd ./${APP_NAME}
      - docker build . -t ${CONTAINER_IMAGE}
    only:
      - branches
    except:
      - master
    tags:
      - shell
      - gitlab-runner01

  deploy_web_demo:
    stage: deploy
    variables:
      SERVICE_DOMAIN: gitlab-service.example.com
    before_script:
      - docker rm -f ${CONTAINER_NAME} || true
    script:
      - docker run --name ${CONTAINER_NAME} -p 80:8080 -d ${CONTAINER_IMAGE}
      - sleep 3
      - curl http://${SERVICE_DOMAIN}/${APP_NAME}
    only:
      - master
    when: manual
    environment:
      name: production
      url: http://${SERVICE_DOMAIN}/${APP_NAME}/
    tags:
      - shell
      - gitlab-runner01  

なるほど、大まかにイメージはできてきた

[GitLab CD] 継続的デプロイ: Pipeline

デプロイを自動化してリリースの安定化が求められる
Pipelineにてjobを組み合わせ、デプロイをコードによって自動化する機能
Review Appsでアーティファクトの確認

### ステージの定義
.gitlab-ci.yml

job01:
  stages:
    - build
    - test
    - deploy

  Build_Job01:
    stage: build
    script:
      - "sudo docker run centos:latest echo Build01"

  Test_Job1:
    stage: test
    script:
      - "sudo docker run centos:latest echo Test01"

  Test_Job2:
    stage: test
    script:
      - "sudo docker run centos:latest echo Test02"

  Deploy_Job1:
    stage: deploy
    script:
      - "sudo docker run centos:latest echo Deploy01"

stageのリストに記載した順番に実行される
whenパラメータ: on_success, on_failure, always, manual

### whenパラメータの例

job01:
  stages:
    - build
    - cleanup_build

  Build_Job01:
    stage: build
    script:
      - "docker run centos:latest echo BuildProcess"

  Cleanup_Build_Job01:
    stage: cleanup_build
    script:
      - "docker rm -f $(sudo docker ps -qa --filter 'status=exited')"
    when: on_failure

### dependenciesパラメータの例

job01:
  stages:
    - build
    - test
    - deploy

  variables:
    APP_NAME: 'web_demo'
    CONTAINER_NAME: ${CI_PROJECT_NAME}_${APP_NAME}

  Build_app01:
    stage: build
    script:
      - cd ./app01
      - gradle war
    artifacts:
      paths:
        - app01/build/libs/*.war

  Build_app02:
    stage: build
    script:
      - cd ./app02
      - gradle war
    artifacts:
      paths:
        - app02/build/libs/*.war

  test_app01:
    stage: test
    script:
      - cd ./app01
      - gradle test
    dependencies:
      - build_app01

  test_app02:
    stage: test
    script:
      - cd ./app02
      - gradle test
    dependencies:
      - build_app02

  deploy:
    stage: deploy
    script:
      - cp app*/build/libs/*.war /usr/local/tomcat/webapps
      - systemctl start tomcat.service

  build_web_demo:
    stage: build
    image: gradle:4.4.1-jdk8
    script:
      - cd ./${APP_NAME}
      - gradle war
      - gradle test
    artifacts:
      paths:
        - ${APP_NAME}/build/libs/*war
      expire_in: 10 min
    tags:
      - docker
      - gitlab-runner01

  test_web_demo:
    stage: test
    variables:
      TEST_CONTENT: GitLab
    script:
      - docker run --name ${CONTAINER_NAME} -d ${APP_NAME}
      - sleep 5
      - export CONTAINER_ADDRESS='docker inspect -f "{{ .NetworkSettings.IPAddress}}" ${CONTAINER_NAME}'
      - wget --post-data="name=${TEST_CONTENT}" http://${CONTAINER_ADDRESS}:8080/${APP_NAME}/hello
      - grep ${TEST_CONTENT} ./hello
    after_script:
      - rm -v ./hello
      - docker rm -f ${CONTAINER_NAME} || true
    tags:
      - shell
      - gitlab-runner01

  deploy_web_demo:
    stage: deploy
    variables:
      SERVICE_DOMAIN: gitlab-service.example.com
    before_script:
      - docker rm -f ${CONTAINER_NAME} || true
    script:
      - docker run --name ${CONTAINER_NAME} -p 80:8080 -d ${APP_NAME}
      - sleep 3
      - curl http://${SERVICE_DOMAIN}/${APP_NAME}/
    tags:
      - shell
      - production-gitlab-runner01

Dockerfile

FROM tomcat:latest
COPY build/libs/*.war /usr/local/tomcat/webapps
CMD ["catalina.sh", "run"]

うーむ、build, test, deployを書いていくのはわかった。

[GitLab CI/CD Jobs] 基本設定

GitLab CI/CDにおけるジョブは「.gitlab-ci.yml」に定義する

.gitlab-ci.yml

job01:
  script:
    - uname -r
    - ps
    - hostname

Job02:
  script:
    - ./build.sh
    - ./test.sh

– Scriptパラメータ利用例

job01:
  script:
    - uname -a
    - ./scripts/build.sh
    - bundle exec rspec spec/requests/

– only, expectパラメータ

job01:
  only:
    - /^script-.*$/
  except:
    - tags

only, exceptで使用できるオプション
branches, tags, pushes, schedules, web

– variablesパラメータ

job01:
  variables:
    PROXY_PATH: 'http://proxy.example.com'
    FLAGS: '-0'
  script:
    - 'https_proxy=$PROXY_PATH curl $FLAGS https://gitlab.com/gitlab-org/gitlab-ce/repository/archive.tar.gz'

– tagパラメータ
プロジェクト内で実行可能なRunnerのリストから特定のRunnerを選択する際に使用
指定したタグを利用し、それにマッチしたRunnerだけにジョブを渡す

job01:
  tags:
    - shell
    - gitlab-runner01

– artifactsパラメータ
ジョブの実行結果をアーティファクトとして保存する際の定義を行う
name, untracked, when, expire_in

job01:
  artifacts:
    name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}"
    untracked: true
    expire_in: 10 min
    paths:
      - ./artifacts

### pythonを実行するサンプル

job01:
  script:
    - python ./scripts/hello.py
  only:
    - master
  tags:
    - shell
    - gitlab-runner01

.gitlab-ci.ymlでbuildとテストを自動化するところまではわかった。
.gitlab-ci.ymlでDockerのbuildをどうやるかが問題か…

[GitLab] CI(継続的インテグレーション)

継続的CIにはJenkins, Travis CI, Circle CIなどがよく利用される
GitLab CI/CDのジョブ機能を使うことによって、ビルドツールやテストツールと連携したインテグレーションの自動化が可能となる

### GitLab CI/CD Jobs
– マルチプラットフォーム: Go, Linux, Windows, FreeBSD, Dockerなどどのプラットフォーム上でもジョブが実行可
– Merge Requestとの連携: Merge Request後のビルド実行確認ができる
– 並列分散実行: 複数のGitLab runnerプロセスにより並列にビルド実行が可能
– オートスケール: ジョブのオートスケールを実現
– アーティファクトの管理: ブラウザ上から利用可能
L Dockerのレジストリ機能とも簡単に連携できる

### GitLab Runner
GitLab CI/CD上から指示されたスクリプトを実行したり、一時的にDockerコンテナを生成してジョブを実行するプロセス
※コンテナをRunnerする場合は2通りある
1. DockerホストにRunnerをインストールしてコンテナをジョブとして起動
2. DockerコンテナをRunnerとして、コンテナ内でジョブを実行

### Executorの種類
– Shell Executor: Runnerが導入されているサーバ上でビルドやテストを実行できるシンプルなExcecutor
– Docker Executor: Docker APIを通してDocker Engineと接続することによって、コンテナから各ビルド作業を実行
– Virtual Box Executor: VirtualBoxのVMを利用したビルド環境を提供 sshとbashを経由
– SSH Executor: SSH接続可能な特定サーバに対してコマンドをSSH経由で送りつける
– Kubernetes Executor: Kubernetes API経由でクラスタ上のPodを作成してビルドを実施。.gitlab-ci.yml内で定義されたServiceパラメータごとに新たにコンテナが生成されビルド、テストを実施

### Runnerの種類
Shared Runners(共有のRunnerで処理)とSpecific Runners(特定のプロジェクトのジョブのみ実行)の2種類がある
Go言語で作成されており、1つのプロセスで複数のExecutorを登録できる

GitLab CI/CD 入門

### Gitlab CI/CDとは
– Gitlabリポジトリ内で.gitlab-ci.ymlで定義するCI/CDの仕組み
– 一つのまとまった処理の単位をpipelineとし、pipelineはjobの集合
– jobはstageによってカテゴライズ・順序付けができ、シーケンシャルにもパラレルに実行できる
– Gitlab CI/CDの実行主体はrunnerという
– RunnerにはDocker, Kubernetes, Virtualbox, Parallels executor, SSH, Shell executorなどがある
– GitlabServerをローカルに建て、リモートレポジトリとして扱うこともできる

.gitlab-ci.yml

stages:
  - prepare
  - echo

prepare-job:
  stage: prepare
  script:
    - echo "Prepare before echo-job..."

echo-job:
  stage: echo
  script:
    - echo "Ahoy! This is Gitlab CI/CD!"

$ tree
.
└── test.html
└── .gitlab-ci.yml

stage:では、pipelineにおけるjobの実行順序を制御
prepare-job, echo-jobはjobの定義

### Gitlab runnerについて
jobはrunner上で実行される
– shared runner
  – Gitlab.comのリソースを共有する形でjobを実行するRunner
– specific runner
— GitlabRunnerを導入した環境でtokenを用いてregisterすることでgitlabと連携し、ci/cdが実行される

### 実際の運用上での.gitlab-ci.yml

# ------------------------------------------------------------#
#  ECS Service
# ------------------------------------------------------------#
  ECSService:
    Type: AWS::ECS::Service
    DependsOn: ALBListener
    Properties:
      Cluster: !Ref ECSCluster
      DesiredCount: !Ref ECSTaskDesiredCount
      LaunchType: FARGATE
      LoadBalancers:
        -
          TargetGroupArn: !Ref TargetGroup
          ContainerPort: 80
          ContainerName: !Sub "${PJPrefix}-${ECSContainerName}"
      NetworkConfiguration:
       AwsvpcConfiguration:
           AssignPublicIp: ENABLED
           SecurityGroups:
             - !Ref ECSSecurityGroup
           Subnets:
             - { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-a" }
             - { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-c" }
      ServiceName: !Sub "${PJPrefix}-${ECSServiceName}"
      TaskDefinition: !Ref ECSTaskDefinition

ここに、DeploymentController:Type: CODE_DEPLOYを追記しないといけなさそう
一旦、cloudformationを削除して、stackを以下に変更します。

  ECSService:
    Type: AWS::ECS::Service
    DependsOn: ALBListener
    Properties:
      Cluster: !Ref ECSCluster
      DesiredCount: !Ref ECSTaskDesiredCount
      DeploymentController:
        Type: CODE_DEPLOY

なんか上手くいったけど、今度はtarget-groupが2つ必要とエラーが出るな…

GitLabとは?

GitLabはGitLab社が公開しているGitサービス
無料で利用できるCEと有料で利用できるEEがある
Githubの後発として開発されたサービス
グループプライベートリポジトリを作れる

### Githubとの違い
– 他のツールとの連携が充実
– デザインはGithubの方が操作しやすいが、Gitlabはトレンドに沿っている
– ジョブの実行ができる
– 安定性はGithubの方が安定している
– ユーザー数はGithubは5600万人以上(2021)、Gitlabは10万人(2017)でダントツにGithubの方が多い
– GitLab独自のCI/CDが提供されている(Java関連のCI/CDも人気)

– リポジトリのグルーピングが好評

git commitしてmergeする

github使ってると、なんか変な感じだな