GitLab CI、Docker、Gradle、JUnit、Mochitoといった各種CI/CDツールを連携し、テストとビルドを自動化、またビルドによって出来上がったDockerイメージをDockerレジストリにデプロイするまでの一連の流れをまとめました。
動作環境
本稿の動作環境は以下の通りです。
ホストマシン
分類 | 項目 | バージョン |
---|---|---|
Amazon EC2 | AMI ID | ami-29d1e34e(CentOS Linux 7 x86_64) |
Amazon EC2 | インスタンスタイプ | t2.medium |
Amazon EC2 | OSバージョン | CentOS Linux release 7.3.1611 (Core) |
Dockerマシン | Docker CE | 17.06.0-ce |
Dockerコンテナ | GitLab CE | 9.4.5 |
Dockerコンテナ | GitLab Runner | 9.4.2 |
開発者マシン
項目 | バージョン |
---|---|
Gradle | 3.2.1 |
Open JDK | 1.8.0_141 |
前提条件
- Dockerホストマシン上でGitLabコンテナが起動していること
- 以下の設定(値は任意)の初期プロジェクトが準備できていること
項目 | 値 |
---|---|
グループ名 | example |
プロジェクト名 | gitlab-ci-demo |
- 開発者はGitLabのプロジェクトにおいてmasterブランチにpushすることが可能な権限(Owner以上)を有していること
- 開発者はプロジェクトのリモートリポジトリとssh接続できること
- 開発者のマシン環境にGradleとOpen JDKが予めインストールされていること
「GitLab CI」を理解する
「GitLab CI」とは
GitLab CIはCI(Continuous Integration、継続的インテグレーション)ツールの一つです。GitLab 7.14から8.0へのメジャー・アップデートにより、GitLab CIはバージョン管理機能を有したGitLab CE/EEに統合されました。
From 7.14 to 8.0 | GitLab.org / GitLab Community Edition · GitLab
「GitLab Runner」とは
「GitLabサーバー」と「GitLab Runner」の役割
GitLabを用いて継続的インテグレーションを行うためには、「GitLabサーバー」とは別にジョブを実行するための「GitLab Runner」というサーバーが必要になります。以下にGitLabサーバーとGitLab Runnerの役割を示します。
-
GitLabサーバー(CIサーバー、Coordinator)
Jenkinsにおけるマスターの役割を担うサーバーです。GitLabのプロジェクトで管理しているブランチへのプッシュやマージリクエストをトリガーとして、GitLab Runnerを呼び出します。 -
GitLab Runner
Jenkinsにおけるスレーブの役割を担うサーバーです。サーバー内の環境でシェルを実行したり、一時的にDockerコンテナを生成してジョブを実行します。
Coding the Next Build | SlideDeck.io
GitLab Runnerの実行方式「Executor」とは
GitLab Runnerには「Executor」と呼ばれるジョブの実行方式があります。本稿ではDockerイメージをデプロイするため、Docker Executorを使用します。
Executorの種類
-
Docker(GitLab推奨)
Runnerとは別に一時的に生成したDockerコンテナの環境内でジョブを実行します。ジョブを実行する度にコンテナを新しく生成するため、実行するジョブの冪等性が保証されます。 -
Shell(GitLab非推奨)
Runnerの環境内でジョブを実行します。ジョブを実行する際にRunnerの環境をクリーンアップしないため、実行するジョブの冪等性が保証されません。またShellによるRunnerの実行はGitLabサーバー上の他プロジェクトのソースコードを取得することができてしまうため、GitLabはこの実行方式を非推奨としています。
Security | Shell - GitLab Documentation -
その他のExecutor
その他にも以下のExecutorがあります。
Executors | GitLab.org / gitlab-ci-multi-runner · GitLab- Docker Machine and Docker Machine SSH (auto-scaling)
- Parallels
- VirtualBox
- SSH
- Kubernetes
サーバー管理者が行う作業
Dockerレジストリを構築する
まずは自動デプロイするDockerコンテナのデプロイ先であるDockerレジストリを構築します。
Dockerレジストリを起動する
任意のパスにdocker-compose.ymlを作成します。
ディレクトリ構成
registry
└── docker-compose.yml
docker-compose.yml
version: '3'
services:
registry:
image: registry:2
tty: true
container_name: registry
restart: always
ports:
- "5000:5000"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Dockerレジストリを起動します。
$ docker-compose up -d
Dockerレジストリの動作確認をする
Dockerレジストリが正常に動作しているかを確認するため、テスト用のイメージである「hello-world」をpullします。
$ docker pull hello-world
pullした「hello-world」イメージにタグを付与します。
$ docker tag hello-world localhost:5000/hello-world
タグが付与されたイメージをDockerレジストリにpushします。
docker push localhost:5000/hello-world
curlコマンドを入力して以下のような応答があれば成功です。
$ curl http://localhost:5000/v2/_catalog
{"repositories":["hello-world"]}
Docker Registry | Docker Documentation
プライベートなDockerレジストリサーバーをコンテナで立てる - Qiita
Dockerプライベートリポジトリ(Docker Registry)構築レシピ | Developers.IO
GitLabサーバーとGitLab Runnerを連携する
続いてGitLab Runnerを構築します。
GitLab Runnerコンテナを起動する
RunnerのRegistration tokenを確認する
Runnerを作成するにはGitLabサーバーに固有の「Registration token」が必要となります。管理者権限を有するユーザーでGitLabにログインし、以下のURLから「Registration token」を確認します。
GitLab / Admin Area > Runners
http://[GitLabサーバーのURL]/admin/runners
GitLab RunnerでDockerコンテナをビルドする方法について
GitLab RunnerでDockerコンテナをビルドする方法を以下に示します。本稿では「Docker socket binding」を利用します。
Using Docker Build - GitLab Documentation
-
docker-in-docker executor(GitLab推奨)
Runnerのexecutorオプションにdocker
を指定し、「ジョブを実行するコンテナ(Executor)」として「docker-in-docker (dind) 」と呼ばれるDockerイメージを使用する方法です。Dockerホスト上にあるExecutorをDockerマシンとすることでDockerコマンドを実行します。 -
Docker socket binding
Runnerのexecutorオプションにdocker
を指定し、ExecutorにRunnerの/var/run/docker.sock
(Dockerのデーモンプロセスである「dockerd」と通信するためのUNIXドメインソケット)をマウントする方法です。RunnerはDockerホストの/var/run/docker.sock
をマウントしているため、間接的にDockerホストのDockerデーモンを使ってDockerコマンドを実行することができます。ただし、Executorに/var/run/docker.sock
をマウントすることによって脆弱性が生じるため、使用する際は注意が必要です。
Dockerコンテナ内からホストマシンのルートを取る具体的な方法(あるいは/var/run/docker.sockを晒すことへの注意喚起) | 48JIGEN Reloaded
Dockerでホストを乗っ取られた - Qiita -
shell executor(GitLab非推奨)
Runnerのexecutorオプションにshell
を指定し、シェルスクリプトからDockerコマンドを実行する方法です。この方法を利用するにはgitlab-runner
ユーザーをdocker
グループに追加する必要があり、gitlab-runner
ユーザーはDockerコンテナを利用して間接的にDockerホストにある全てのファイルにアクセスすることができるため、GitLabはこの方法を非推奨としています。
On Docker security: 'docker' group considered harmful - Andreas Jung
本稿で「Docker socket binding」を採用する理由
Docker Registryとの接続は「localhost」で指定する方法とIPアドレスで指定する方法がありますが、IPアドレスを指定して接続する場合はHTTPSしか許可されておらず、また自己証明書を使用した場合は接続を拒否されてしまいます。
本稿ではデプロイ先としてDockerホスト上のローカルレジストリ(localhost:5000)を指定しています。「docker-in-docker executor」の場合、dindイメージのExecutorからはDockerホスト上にあるローカルレジストリをhttp://localhost:5000
で参照することができないため、本稿では「Docker socket binding」を採用しています。その他に「docker-in-docker executor」を使用してdindの起動コマンドに--insecure-registry
オプションを使う方法が考えられます。
GitLab Runnerのdocker-compose.ymlを作成する
任意のパスにdocker-compose.ymlを作成します。本稿におけるディレクトリ構成を以下に示します。
ディレクトリ構成
runner/
└── docker-compose.yml
runner/docker-compose.yml
version: '3'
services:
runner:
image: gitlab/gitlab-runner:alpine-v9.4.2
tty: true
container_name: docker-executor
restart: always
environment:
- REGISTER_NON_INTERACTIVE=true
- CI_SERVER_URL=http://[GitLabサーバーのURL]:9090/ci
- REGISTRATION_TOKEN=xxxxxxxxxxxxxxxxxxxx
- RUNNER_EXECUTOR=docker
- RUNNER_TAG_LIST=docker
- RUNNER_NAME=Docker Executor (Docker socket binding)
- RUNNER_LIMIT=1
- DOCKER_IMAGE=docker:latest
- DOCKER_VOLUMES=/var/run/docker.sock:/var/run/docker.sock
volumes:
- /srv/gitlab-runner/config:/etc/gitlab-runner
- /var/run/docker.sock:/var/run/docker.sock
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Docker image installation and configuration / Run GitLab Runner in a container - GitLab Documentation
Use Docker socket binding | Using Docker Build - GitLab Documentation
GitLab Runnerの環境変数
environmentに定義している環境変数についての説明を以下に示します。
環境変数 | 説明 |
---|---|
REGISTER_NON_INTERACTIVE | ビルド時のインタラクティブな問い合わせを無効にします。 |
CI_SERVER_URL | CIサーバーのURLを指定します。 |
REGISTRATION_TOKEN | GitLabサーバーのRegistration Tokenを指定します。 |
RUNNER_EXECUTOR | Executor(shell、dockerなど)を指定します。 |
RUNNER_TAG_LIST | Runnerのタグ名を定義します。定義したタグはジョブで指定することができます。 |
RUNNER_NAME | Runnerの説明を定義します。 |
RUNNER_LIMIT | ジョブの最大同時実行数を指定します。 |
DOCKER_IMAGE | ジョブを実行するコンテナがベースとするデフォルトの Dockerイメージを指定します。 |
DOCKER_VOLUMES | ジョブ用のコンテナ実行時にマウントするボリュームを 指定します。 |
本稿では「Docker socket binding」を使用するため、GitLab Runnerの環境変数 DOCKER_VOLUMES
に/var/run/docker.sock:/var/run/docker.sock
を指定してRunnerのUNIXドメインソケットをExecutorにマウントしています。
GitLab Runnerで指定できるその他の環境変数はRunnerコンテナ上で以下のコマンドを入力することで確認できます。
$ gitlab-runner register --help
GitLab Runnerを起動する
以下のコマンドを入力してRunnerコンテナを起動します。
$ docker-compose up -d
GitLabサーバーにGitLab Runnerを登録する
GitLab Runnerコンテナを起動しただけではGitLabサーバーに認識されません。以下のコマンドを入力してGitLabサーバーにGitLab Runnerを登録します。
$ docker exec -it docker-executor gitlab-runner register
docker exec -it docker-executor gitlab-runner register
Running in system-mode.
Registering runner... succeeded runner=gFFiecFD
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
以下のURLから、GitLab RunnerがGitLabサーバーに登録されていることを確認することができます。
GitLab / Admin Area > Runners(http://[GitLabサーバーのURL]/admin/runners)
GitLabサーバーにおける「Runner」の分類
GitLabサーバーはGitLab Runnerを以下の二種類のRunnerに分類して管理します。
-
Shared Runner
プロジェクト共通で使用できるRunnerです。ジョブのキューは「Fair usage queue」と呼ばれるアルゴリズムで実行されます。 -
Specific Runner
プロジェクトに固有のRunnerです。ジョブのキューはFIFO形式で実行されます。
GitLab RunnerはデフォルトではShared Runnerとして扱われます。「GitLab / Admin Area」 > 「Runners」のページから「Restrict projects for this Runner」に表示されている「group」を「Enable」にすることで「Specific Runner」に切り替えることができます。ただし、 一度Specific Runnerにした場合、Shared Runnerに戻すことができないため注意が必要です。
Shared vs specific Runners | Runners - GitLab Documentation
また「Run untagged jobs」にチェックを入れることで、タグが付与されていないジョブに対してもGitLab Runnerを実行することができます。
開発者が行う作業
Gradleプロジェクトを作成する
本稿はGitLab CIの動作を理解することが目的のため、git-flowによるブランチ管理は割愛してmasterブランチを直接編集します。
GitLabプロジェクトをクローンする
プロジェクトを配置するディレクトリは任意ですが、本稿ではホームディレクトリ直下にプロジェクトを作成します。以下のコマンドを入力してGitLabからプロジェクトをクローンします。
$ cd ~
$ git clone ssh://git@[GitLabサーバーのIPアドレス]:[SSHポート]/example/gitlab-ci-demo.git
正常にクローンできていれば「gitlab-ci-demo」ディレクトリが作成されていることを確認できます。
$ ls
gitlab-ci-demo
.gitignoreを作成する
Gitのコミット時に不要なファイルが混入することを避けるため、.gitignoreファイルを作成します。
gitignore.io - Create Useful .gitignore Files For Your Project
上記のサイトで「Git」、「Java」、「Gradle」、「Eclipse」と入力し、「Create」ボタンを入力することで.gitignoreファイルを自動生成してくれます。生成されたファイルは以下のパスに配置します。
gitlab-ci-demo/.gitignore
Gradleプロジェクトを作成する
以下のコマンドを入力し、Gradleプロジェクトを作成します。
$ gradle init --type java-library
Starting a Gradle Daemon (subsequent builds will be faster)
:wrapper
:init
BUILD SUCCESSFUL
Total time: 4.775 secs
gradle initコマンドで指定できるtypeについて
-
java-library
Jarライブラリを作成する場合に指定するtypeです。Warライブラリを作成する場合もこのtypeを指定し、不足するディレクトリは手動で作成します。 -
java-application
コマンドラインによるJavaアプリケーションを作成する場合に指定するtypeです。 -
その他のtype
- pom
- scala-library
- groovy-library
- groovy-application
- basic
./gradle help --task init
と入力することでデフォルトで定義されているtypeを確認することができます。
Build Init Plugin - Gradle User Guide Version 4.1
Gradleラッパーを作成する
GradleラッパーはGradleプロジェクトをビルドする時に利用するラッパースクリプトです。Gradleラッパーが提供するシェルスクリプト./gradlew
を実行することでGradleが自動的にダウンロードされ、Gradleコマンドと同じ処理を実行できます。Gradleラッパーはプロジェクトを作成した時と同じバージョンのgradleを自動でインストールします。同じバージョンを使用することで、開発者によって異なる環境が原因でビルドを実行することができないといった状況を回避することができます。
Gradle初心者によるGradle事始め - Qiita
第62章 Gradleラッパー
以下のコマンドを入力し、Gradleラッパーを作成します。
$ gradle wrapper
以下のコマンドを入力し、Gradleラッパーが正しくインストールされているかを確認します。
$ ./gradlew --version
------------------------------------------------------------
Gradle 3.2.1
------------------------------------------------------------
Build time: 2016-11-22 15:19:54 UTC
Revision: 83b485b914fd4f335ad0e66af9d14aad458d2cc5
Groovy: 2.4.7
Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM: 1.8.0_141 (Oracle Corporation 25.141-b15)
OS: Linux 3.10.0-514.16.1.el7.x86_64 amd64
ここまでの操作で「gitlab-ci-demo」プロジェクト配下は以下のような構成になっているはずです。
gitlab-ci-demo
|-- build.gradle
|-- gradle
| `-- wrapper
| |-- gradle-wrapper.jar
| `-- gradle-wrapper.properties
|-- gradlew
|-- gradlew.bat
|-- settings.gradle
`-- src
|-- main
| `-- java
| `-- Library.java
`-- test
`-- java
`-- LibraryTest.java
「Library.java」と「LibraryTest.java」は不要なサンプルファイルのため削除しておきます。
$ rm ~/gitlab-ci-demo/src/main/java/Library.java \
~/gitlab-ci-demo/src/test/java/LibraryTest.java
外部パッケージを定義する
デフォルトのbuild.gradleを編集し、Javaファイルをテスト・ビルドする際に必要となる外部パッケージを定義します。
~/gitlab-ci-demo/build.gradle
/*
* This build file was auto generated by running the Gradle 'init' task
* by 'programmer1' at '8/18/17 5:04 PM' with Gradle 3.2.1
*
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* user guide available at https://docs.gradle.org/3.2.1/userguide/tutorial_java_projects.html
*/
// Apply the java plugin to add support for Java
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'eclipse'
// In this section you declare where to find the dependencies of your project
repositories {
// Use 'jcenter' for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
// In this section you declare the dependencies for your production and test code
dependencies {
// The production code uses the SLF4J logging API at compile time
compile 'org.slf4j:slf4j-api:1.7.21'
// Declare the dependency for your favourite test framework you want to use in your tests.
// TestNG is also supported by the Gradle Test task. Just change the
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script.
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.7.19'
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
}
build.gradle.origin(編集前)とbuild.gradle(編集後)の差分
--- build.gradle.origin 2017-08-18 17:10:45.334725608 +0000
+++ build.gradle 2017-08-18 17:21:52.897550222 +0000
@@ -9,6 +9,8 @@
// Apply the java plugin to add support for Java
apply plugin: 'java'
+apply plugin: 'war'
+apply plugin: 'eclipse'
// In this section you declare where to find the dependencies of your project
repositories {
@@ -27,4 +29,6 @@
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script.
testCompile 'junit:junit:4.12'
+ testCompile 'org.mockito:mockito-core:2.7.19'
+ providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
}
apply plugin
としてwar
とeclipse
を追加し、またdependencies
にmockito-core
とjavax.servlet-api
を追加しました。
dependenciesで記述したパッケージが正しく定義されているかを確認します。以下のコマンドを入力してFAILED
が表示されていなければ問題ありません。
$ gradle dependencies
「apply plugin」とは
build.gradleに追加した「apply plugin」についての説明を以下に示します。
プラグインID | 説明 |
---|---|
Java | Javaのコンパイル、テスト、バンドル機能をプロジェクトに追加します。 |
war | ウェブアプリケーションのWARファイルをビルドできるようにします。 |
eclipse | Eclipse IDEが使用するファイルを生成し、プロジェクトをEclipseにインポートできるようにします。 |
「repositories」とは
本稿ではデフォルトと同じ「jcenter」というリポジトリを使用しています。「repositories」で指定したリポジトリからパッケージがダウンロードされます。「jcenter」以外で良く使用されるリポジトリとして「mavenCentral」があります。ただし最近は「jcenter」を指定することが推奨されているようです。
Android Studio – Migration from Maven Central to JCenter | Blog @Bintray
-
jcenter()
Bintray jcenter - Maven, Gradle, Ivy, SBT, Groovy, Clojure central repository -
mavenCentral()
Maven Repository: Search/Browse/Explore
「dependencies」とは
「dependencies」には必要な外部パッケージと併せて以下の依存関係を指定します。
名前 | 意味 |
---|---|
compile | プロジェクトのプロダクトコードをコンパイルするのに必要な依存関係 |
runtime | プロダクトのクラスを実行するときに必要になる依存関係。デフォルトで、コンパイル時の依存関係もここに含まれる。 |
testCompile | プロジェクトのテストコードをコンパイルするのに必要な依存関係。デフォルトで、コンパイルされたプロダクトクラスと、コンパイル時の依存関係も含まれる。 |
testRuntime | テストを実行するのに必要な依存関係。デフォルトで、compile、runtime、testCompileの各依存関係もここに含まれる。 |
providedCompile | warプラグインによって追加されるコンフィグレーション。compileと同じスコープだが、WARアーカイブに含まれない。 |
「junit」と「mockito-core」はテストにおけるコンパイル時のみ必要なパッケージであり、ビルド時には不要なパッケージであるため、testCompile
を指定しています。
また本稿ではビルドによって出来上がったwarファイルをTomcatサーバーに配備します。「javax.servlet-api」はTomcatに含まれており、warファイルに含める必要がないためprovidedCompile
を指定しています。
第8章 依存関係管理の基本
Dependency management
Eclipseプロジェクトを作成する
本稿ではviでファイルを作成するため必須の作業ではありませんが、開発者がEclipseを使ってファイルを編集する場合はコンソールから以下のgradleコマンドを実行します。
$ ./gradlew eclipse
コマンドを入力することでEclipseプロジェクトに必要な以下のファイルが生成されます。
- .classpath
- .project
- .settings
第38章 Eclipse プラグイン
EclipseのGradleプロジェクト作成方法比較 - Qiita
備忘録!GradleでWARを作る - Qiita
Webアプリケーションを作成する
Gradleが公開している「Building Java Web Applications | Gradle Guides」
の例に従ってソースコードを配備します。
基本的にGradleが公開しているソースコードをそのまま利用していますが、一部誤りがあるため注意してください。以下に修正箇所を示します。
修正箇所 | 行番号 | 修正前 | 修正後 |
---|---|---|---|
HelloServlet.javaのパス | - | src/main/java/com/gradle/demo/ | src/main/java/org/gradle/demo/ |
HelloServlet.java | 10行目 | urlPatterns = {"hello"} | urlPatterns = {"/hello"} |
プロジェクトのレイアウト
以下はWebアプリケーションに必要なソースコード作成後のディレクトリ構成です。
.
├── Dockerfile
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── org
│ │ └── gradle
│ │ └── demo
│ │ └── HelloServlet.java
│ └── webapp
│ ├── index.html
│ └── response.jsp
└── test
└── java
└── org
└── gradle
└── demo
└── HelloServletTest.java
サーブレットを配備する
まずはサーブレットをsrc/main/java
配下に作成します。
$ mkdir -p ~/gitlab-ci-demo/src/main/java/org/gradle/demo
$ vi ~/gitlab-ci-demo/src/main/java/org/gradle/demo/HelloServlet.java
~/gitlab-ci-demo/src/main/java/org/gradle/demo/HelloServlet.java
package org.gradle.demo;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "HelloServlet", urlPatterns = {"/hello"}, loadOnStartup = 1)
public class HelloServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().print("Hello, World!");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
if (name == null) name = "World";
request.setAttribute("user", name);
request.getRequestDispatcher("response.jsp").forward(request, response);
}
}
「@WebServlet」とは
Servlet3.0から導入されたServlet用のアノテーションより、これまでweb.xmlに記述していた設定値をアノテーションで記述できるようになりました。
Javaの道:Servlet(14.アノテーション)
urlPatternsの書式
WebServletアノテーションで指定するurlPatternsの書式を以下に示します。
書式 | 説明 |
---|---|
/??? | 正確にURLが合致した場合にサーブレットが起動します。 |
/???/* | /???/で始まる全てのURLでアクセスがあった場合に、サーブレットが起動します。 例:「/resource/*」と指定した場合は、「resource」で始まる全てのURLにマッチします。 |
*.??? | ???を拡張子にもつ全てのURLでアクセスがあった場合に、サーブレットが起動します。 例:「*.cgi」と指定した場合は、「cgi」を拡張子に持つURL全てにマッチします。 |
/ | 適応するものが無かった場合に実行される、デフォルトサーブレットを示します。 |
1. サーブレットの設定と実行 (3) | TECHSCORE(テックスコア)
「load-on-startup」とは
サーブレットは初めてリクエストされた時にインスタンス化されるため、最初のリクエストがあった時に初期化パラメータを読み込むことができます。load-on-startup要素を指定すると、アプリケーションがロードされた時に、指定したサーブレットがインスタンス化され、サーブレット内のinit()メソッドが実行されます。load-on-startupタグに定義している数字はロード順です。アプリケーションロード時に複数のサーブレットをロードしておく必要がある場合は、1、2、3という風にロード順番を設定します。
load-on-startupの利用-サーブレット(servlet)入門:IT TRICK
htmlとjspを配備する
Gradleのwarプラグインはデフォルトでsrc/main/webapp
配下のファイルをjarに含める設定になっています。初期のディレクトリ構成では「webapp」ディレクトリが存在しないため新規作成します。
第10章 Webアプリケーションクイックスタート
$ mkdir ~/gitlab-ci-demo/src/main/webapp
$ vi ~/gitlab-ci-demo/src/main/webapp/index.html
~/gitlab-ci-demo/src/main/webapp/index.html
<html>
<head>
<title>Web Demo</title>
</head>
<body>
<p>Say <a href="hello">Hello</a></p>
<form method="post" action="hello">
<h2>Name:</h2>
<input type="text" id="say-hello-text-input" name="name" />
<input type="submit" id="say-hello-button" value="Say Hello" />
</form>
</body>
</html>
$ vi ~/gitlab-ci-demo/src/main/webapp/response.jsp
~/gitlab-ci-demo/src/main/webapp/response.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello Page</title>
</head>
<body>
<h2>Hello, ${user}!</h2>
</body>
</html>
テストクラスを配備する
$ mkdir -p ~/gitlab-ci-demo/src/test/java/org/gradle/demo
$ vi ~/gitlab-ci-demo/src/test/java/org/gradle/demo/HelloServletTest.java
~/gitlab-ci-demo/src/test/java/org/gradle/demo/HelloServletTest.java
package org.gradle.demo;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
public class HelloServletTest {
@Mock private HttpServletRequest request;
@Mock private HttpServletResponse response;
@Mock private RequestDispatcher requestDispatcher;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void doGet() throws Exception {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
when(response.getWriter()).thenReturn(printWriter);
new HelloServlet().doGet(request, response);
assertEquals("Hello, World!", stringWriter.toString());
}
@Test
public void doPostWithoutName() throws Exception {
when(request.getRequestDispatcher("response.jsp"))
.thenReturn(requestDispatcher);
new HelloServlet().doPost(request, response);
verify(request).setAttribute("user", "World");
verify(requestDispatcher).forward(request,response);
}
@Test
public void doPostWithName() throws Exception {
when(request.getParameter("name")).thenReturn("Dolly");
when(request.getRequestDispatcher("response.jsp"))
.thenReturn(requestDispatcher);
new HelloServlet().doPost(request, response);
verify(request).setAttribute("user", "Dolly");
verify(requestDispatcher).forward(request,response);
}
}
ジョブ設定ファイルを作成する
「.gitlab-ci.yml」とは
「.gitlab-ci.yml」はジョブのテスト手順やビルド手順を記述したGitLab CIのジョブ設定ファイルです。GitLabで管理しているプロジェクト(Gitリポジトリ)のルートディレクトリに配備します。
.gitlab-ci.yml
GitLabプロジェクトのルートディレクトリに「.gitlab-ci.yml」を作成します。
vi ~/gitlab-ci-demo/.gitlab-ci.yml
~/gitlab-ci-demo/.gitlab-ci.yml
stages:
- build
- package
gradle-build:
image: java:8-jdk
stage: build
script:
- ./gradlew build
artifacts:
paths:
- build/libs/*.war
expire_in: 1 week
tags:
- docker
docker-build:
image: docker:latest
stage: package
script:
- docker build -t localhost:5000/runnner-artifact .
- docker push localhost:5000/runnner-artifact
tags:
- docker
Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes | GitLab
項目 | 説明 |
---|---|
stages | stageの実行順序を指定します。 |
gradle-build, docker-build | 任意のジョブ名を指定します。 |
image | Docker Executorを使ってジョブを実行する際のDockerイメージを指定します。 |
stage | 任意のstageを指定します。 |
script | ジョブの実行コマンドを記述します。 |
artifacts | CI においてビルドが正常に完了した後に入手できる成果物をアーティファクトと呼びます。ジョブの実行結果を他のジョブで使う際に記述します。またここで指定した成果物はzipファイルとして GitLab上からダウンロードすることができます。 |
tags | 使用するGitLab Runnerをタグで指定します。 |
はじめてのGitLab-CI - Qiita
artifacts / Configuration of your jobs with .gitlab-ci.yml - GitLab Documentation
GitLab CI/CDでiOSアプリをビルドし、ipaを配布する - Qiita
Dockerfileを作成する
「.gitlab-ci.yml」で記述したdocker build
を実行する際に使用するDockerfileを作成します。
vi ~/gitlab-ci-demo/Dockerfile
FROM tomcat:9.0
COPY build/libs/*.war /usr/local/tomcat/webapps
CMD ["catalina.sh", "run"]
artifactsで指定したbuild/libs/*.war
をtomcatのwebapps配下に展開しています。
自動テスト・ビルド・デプロイを実行する
リモートリポジトリへpushする
作成したソースコードをGitLabプロジェクトのリモートリポジトリへpushします。
$ git add .
$ git commit -m "test gitlab-ci"
$ git push
ジョブを確認する
リモートリポジトリへpushすると自動でジョブが実行されます。ジョブのステータスは以下の画面から確認することができます。
Pipelines > Jobs
Dockerレジストリにデプロイされたコンテナを起動する
以下のコマンドを入力してDockerレジストリにイメージが追加されているかを確認します。"runnner-artifact"
が追加されていればジョブが正しく実行されています。
$ curl http://localhost:5000/v2/_catalog
{"repositories":["hello-world","runnner-artifact"]}
最後に追加されたDockerイメージをコンテナとして起動します。本稿ではtomcatの公開ポートとして8888を指定しています。
docker run -it --rm --name artifact -p 8888:8080 localhost:5000/runnner-artifact
以下のURLを入力して、「Web Demo」画面が表示されれば成功です。
http://[DockerホストのURL]:8888/gitlab-ci-demo/