[Docker] 1回限り動かすコンテナ

コンパイラや画像変換ライブラリなど便利ツールが入っていて、そのツールを使ってDockerホストのファイルを処理したい場合

hello.go

package main

import "fmt"

func main(){
	fmt.Printf("Hello World\n")
}

$ sudo docker run –rm -v “$PWD”:/usr/src/myapp -w /usr/src/myapp golang:1.13 go build -v

–rm: 実行が完了した時にコンテナを破棄
-w /usr/src/myapp: -wは作業ディレクトリ
go build -v: go言語のビルド

$ ./myapp
Hello World

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

[Docker] コンテナのメンテナンス

### Dockerが停止中または作られていない時
docker runの引数に、/bin/sh や /bin/bashなどのシェルプログラムを指定し、規定のコマンドの代わりにこれらのシェルが起動されるようにする
$ sudo docker run –name my-apache-app -it httpd:2.4 /bin/bash
# ls
bin build cgi-bin conf error htdocs icons include logs modules

– デタッチ
[Ctrl] + [P], [Ctrl] + [Q]でデタッチ
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
82c0dbeb972f httpd:2.4 “/bin/bash” 2 minutes ago Up 2 minutes 80/tcp my-apache-app

– アタッチ
$ sudo docker attach my-apache-app

– 終了
# exit
exit
$ sudo docker rm my-apache-app

### 動作中の時
docker execを使う。 docker exec –it ${containerName} /bin/bash

$ sudo docker run –name my-apache-app -dit -p 8080:80 -v “$PWD”:/usr/local/apache2/htdocs/ httpd:2.4 /bin/bash
$ sudo docker exec -it my-apache-app /bin/bash
$ sudo docker stop my-apache-app
$ sudo docker rm my-apache-app
※殆ど場合、docker execを使用する

うん、docker execとdocker runは大分整理されてきた。

PHPExcelを使ってみよう

github: https://github.com/PHPOffice/PHPExcel

なんか古そうだかDLしてみる
$ git clone https://github.com/PHPOffice/PHPExcel.git

<?php

require_once './PHPExcel/Classes/PHPExcel.php';

$objBook = new PHPExcel();

$objSheet = $objBook->getActiveSheet();

$objSheet->setCellValue('A1', 'ABCDEFG');
$objSheet->setCellValue('A2', 123.56);
$objSheet->setCellValue('A3', TRUE);
$objSheet->setCellValue('A4', '=IF(A3, CONCATENATE(A1, " ", A2), CONCATENATE(A2, " ", A1))');
$objWriter = PHPExcel_IOFactory::createWriter($objBook, "Excel2007");
$objWriter->save('test.xlsx');
exit();
?>

$ sudo apt-get install php-zip

うん、OK

[Docker] 基本操作

docker runは docker pull, docker create, docker startを順番に実行する
docker pullはダウンロード済みのときは再度ダウンロードはしない

$ docker pull httpd:2.4

### latest
タグ名を省略したときは最新版を意味するlatestという特殊なタグが指定されたものとみなされます。
本番環境でDockerを利用するのであれば、タグ名を省略せずに明示的に指定して、特定のイメージに固定することが殆ど
コンテナの定期的なアップデートは必須

### Docker コンテナの作成
コンテナを作成するには docker create を使う
$ sudo docker create –name my-apache-app -p 8080:80 -v “$PWD”:/usr/local/apache2/htdocs/ httpd:2.4
オプションを上記では –name, -p, -v を指定しているが、その他にもさまざまなオプションを指定できる

### nameオプションによる名前付
コンテナの名前をつける –nameオプションはほぼ使用する

### pオプションによるポート設定
-pオプションはポート番号をマッピング

### vオプションによるマウント設定
コンテナの特定ディレクトリに、ホストのディレクトリをマウントする設定

### Dockerコンテナの開始と停止
Docker start *

### -dit
「-dit」オプションを指定しなければ、コンテナがフォアグラウンドで実行されてしまう
-d: デタッチモード
-i: インタラクティブモード
-t: 擬似端末を割り当て

なるほどー

[Docker] Apacheのdockerを動かす

Docker hub
https://hub.docker.com/_/httpd
-> httpdをdownloadします

$ sudo docker run -dit –name my-apache-app -p 8080:80 -v “$PWS”:/usr/local/apache2/htdocs/ httpd:2.4

$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4d6766e52c1e httpd:2.4 “httpd-foreground” About a minute ago Up About a minute 0.0.0.0:8080->80/tcp, :::8080->80/tcp my-apache-app

### コンテナの停止と再開
$ sudo docker stop my-apache-app
$ sudo docker start my-apache-app

### ログ出力
$ sudo docker logs my-apache-app

### イメージの破棄
rmを使うにはコンテナが停止状態にならなければいけない
$ sudo docker stop my-apache-app
$ sudo docker rm my-apache-app
$ sudo docker image rm httpd:2.4

なるほど、この辺は基礎というか、ある程度理解している

[Docker] ベースイメージの考え方

Dockerイメージの種類
1. 基本的なLinuxディストリビューションだけのイメージ
2. アプリケーション入りのイメージ
L web server(apache, nginx)
L database server(MySQL, MariaDB, PostgreSQL)
L WordPress, Redmin, Roundcube

業務システムでDockerを使う場合は、LinuxのみDockerイメージを使ってコンテナを作り、そこに自社開発したシステムをインストールして使うことがほとんど
※アプリケーション入りのDockerイメージは、イメージの大きさを小さくするために、最低限のコマンドやライブラリしか入ってなかったり、特殊な初期起動設定がされているため
それをカスタムDockerイメージとして作成する

なるほど、Linux系で開発するのか、、、
非常に勉強になったぜ…

[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をどうやるかが問題か…