20190724のdockerに関する記事は9件です。

terraformの公式イメージをgitlab-ciで使うときの注意点

terraformの公式イメージをgitlab-ciで使うときの注意点

はじめに

terraformの公式イメージを使って、gitlab-ciを実行するときに地味にハマったので注意点書く

使用した .gitlab-ci.yml

.gitlab-ci.yml(修正前)
image: 
  name: hashicorp/terraform:latest

stages: 
  - terraform_validate
  - terraform_plan
  - terraform_apply

before_script:
  - terraform init --upgrade

validate:
  stage: terraform_validate
  script:
    - terraform --version
    - terraform validate

plan:
  stage: terraform_plan
  script: 
    - terraform plan --parallelism=30 -out "planfile"
  artifacts:
    paths:
      - ./planfile

apply:
  stage: terraform_apply
  script: 
    - terraform apply -input=false "planfile"
  dependencies:
    - plan
  when: manual

これを実行した結果

Terraform Commands(CLI)にあるような、terraformコマンドを実行した結果が出てる。

In erroneous cases, a non-zero exit status will be returned.

と書いてあるように、0以外のstatusが返ってきてるため、エラーとなって終了している。

Usage: terraform [-version] [-help] <command> [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

Common commands:
    apply              Builds or changes infrastructure
    console            Interactive console for Terraform interpolations
    destroy            Destroy Terraform-managed infrastructure
    env                Workspace management
    fmt                Rewrites config files to canonical format
    get                Download and install modules for the configuration
    graph              Create a visual graph of Terraform resources
    import             Import existing infrastructure into Terraform
    init               Initialize a Terraform working directory
    output             Read an output from a state file
    plan               Generate and show an execution plan
    providers          Prints a tree of the providers used in the configuration
    refresh            Update local state file against real resources
    show               Inspect Terraform state or plan
    taint              Manually mark a resource for recreation
    untaint            Manually unmark a resource as tainted
    validate           Validates the Terraform files
    version            Prints the Terraform version
    workspace          Workspace management

All other commands:
    0.12upgrade        Rewrites pre-0.12 module source code for v0.12
    debug              Debug output management (experimental)
    force-unlock       Manually unlock the terraform state
    push               Obsolete command for Terraform Enterprise legacy (v1)
    state              Advanced state management
Usage: terraform [-version] [-help] <command> [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

Common commands:
    apply              Builds or changes infrastructure
    console            Interactive console for Terraform interpolations
    destroy            Destroy Terraform-managed infrastructure
    env                Workspace management
    fmt                Rewrites config files to canonical format
    get                Download and install modules for the configuration
    graph              Create a visual graph of Terraform resources
    import             Import existing infrastructure into Terraform
    init               Initialize a Terraform working directory
    output             Read an output from a state file
    plan               Generate and show an execution plan
    providers          Prints a tree of the providers used in the configuration
    refresh            Update local state file against real resources
    show               Inspect Terraform state or plan
    taint              Manually mark a resource for recreation
    untaint            Manually unmark a resource as tainted
    validate           Validates the Terraform files
    version            Prints the Terraform version
    workspace          Workspace management

All other commands:
    0.12upgrade        Rewrites pre-0.12 module source code for v0.12
    debug              Debug output management (experimental)
    force-unlock       Manually unlock the terraform state
    push               Obsolete command for Terraform Enterprise legacy (v1)
    state              Advanced state management
ERROR: Job failed: exit code 127

理由

dockerhubのdockerfileをよく見ろということだ。

https://hub.docker.com/r/hashicorp/terraform/dockerfile

下記にあるように、 ENTRYPOINT ["terraform"]となっている。
そりゃ、terraformコマンドを実行するわけだ。

FROM golang:alpine
MAINTAINER "HashiCorp Terraform Team <terraform@hashicorp.com>"

ENV TERRAFORM_VERSION=0.10.0

RUN apk add --update git bash openssh

ENV TF_DEV=true
ENV TF_RELEASE=true

WORKDIR $GOPATH/src/github.com/hashicorp/terraform
RUN git clone https://github.com/hashicorp/terraform.git ./ && \
    git checkout v${TERRAFORM_VERSION} && \
    /bin/bash scripts/build.sh

WORKDIR $GOPATH
ENTRYPOINT ["terraform"]

結果

何でもいいから、entrypointを取り敢えず上書きするようにしておく。

.gitlab-ci.yml(修正後)
image: 
  name: hashicorp/terraform:latest
  entrypoint:
    - ''

stages: 
  - terraform_validate
  - terraform_plan
  - terraform_apply

before_script:
  - terraform init --upgrade

validate:
  stage: terraform_validate
  script:
    - terraform --version
    - terraform validate

plan:
  stage: terraform_plan
  script: 
    - terraform plan --parallelism=30 -out "planfile"
  artifacts:
    paths:
      - ./planfile

apply:
  stage: terraform_apply
  script: 
    - terraform apply -input=false "planfile"
  dependencies:
    - plan
  when: manual
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

既存のRuby on RailsプロジェクトにJenkins と Docker で CIを導入する

要約

引き継いだプロジェクトなどで既存のRailsアプリにCIがない場合に、気軽にテストを書いてCIを回す文化を醸成したいと思って対応した内容の記録です。

対象読者

Railsのプロジェクトを運用している方で、引き継いだプロジェクトなど何からの事情によりテストを書く環境がない、または、CI環境を構築したいが、日本語の情報が少ない(自分がそうでした)ために構築に苦労している方に向けた記事です。

構成

Untitled Diagram.png

構築手順

1. ビルドマシンの準備

  • 適当なLinuxマシンを用意してください。
  • 今回の例ではCentos7を使用しています。

2. dockerインストール

3. docker-composeインストール

4. Jenkins(スタンドアロン版)のインストール

  • Jenkinsもdockerに閉じ込めたかったのですが、コンテナ上でdocker-compose の使用がうまく動かなかったため、今回はやむなくJenkinsだけは ビルドマシン上にwar配置という形をとりました。
# Jenkinsの起動スクリプト作成
$ mkdir ~/myjkdir
$ cd myjkdir
$ wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war .
$ cat <<EOT> start_jk.sh
JENKINS_JAVA_OPTIONS="-Xmx2048m -XX:MaxPermSize=512m -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true"
nohup java -jar jenkins.war &
EOT
$ chmod +x start_jk.sh
$ chown $USER:$USER start_jk.sh

5. Railsにビルド用の各種設定を行う

  • railsアプリをdockerにのせるための手順はこちらの通りで動作しました。
  • https://docs.docker.com/compose/rails/
  • ※ 後述していますが、この際、採用するイメージのミドルウェアのバージョンは実際に使用しているものに合わせるようにしましょう。コピペで進むとビルド出来ないなど後々不安定な挙動に悩むことになります。

6. ビルドマシンでdocker-composeのイメージビルド

# 適当なディレクトリに上記リポジトリをチェックアウトして、dockerイメージのビルド
cd /myapp_dir
# Checkout from SCM .
docker-compose build
docker images
# エラーなく、イメージがビルドできていることの確認
docker-compose up
# コンテナ起動確認
docker-compose run web bundle exec rake db:create

7. Jenkinsファイルの用意

pipeline {
  agent any
  stages {
    stage('build') {
      steps {
        sh 'echo "Hello World"'
       }
    }
    stage('test') {
      steps {
        sh 'docker-compose run web bundle exec rake db:create'
        sh 'docker-compose run web bundle exec rake db:schema:load'
        sh 'docker-compose run web bundle exec rake test test/**/*.rb'
      }
    }
  }
}

8. Jenkinsでビルドジョブ(pipeline)を作成し実行

  • 無事ビルド完了。 これで、テストを書いていけば自動テストが回りデグレの防止などコード品質向上に 寄与してくれることでしょう。 私も安心して眠れます。(テストを書いてから寝ろ)

はまったポイント

以下では、上記CI環境構築の間にハマったポイントを記載します。

1. 既存アプリのミドルウェアバージョンを良く確認しましょう。

  • レガシーなプロジェクトだと、使用しているソフトウェアのバージョンが古いこともあり、 公式等の記述コピペで進むとうまく動かない状況に陥ります。 docker imageに採用するタグ(バージョン)を良く確認しましょう。
  • ※ 例えばruby2.3とpostgres9.4の組み合わせのシステムの場合

    • Dockerfile
FROM ruby:2.3
...
  • docker-compose.yml
db:
 image: postgres:9.4
...

2. docker関連ファイルの改行コードはLFで統一

所感

テストが気軽にかける環境をローコストで手に入れることはソフトウェア品質向上に寄与すると思っています。Rails単体でも、かなり簡単にテストができる仕組みが入っていると思いますが、さらにDB回りやシステム全体のビルドテストとなると、Dockerみたいなアプリをパッケージにできる仕組みで手軽に作って捨てる環境を作りたいところですが、現状まだまだ設定が煩雑だったり日本語情報が少なかったりと、環境構築に障壁を感じました。少しでもこの記事が同じような境遇の方のお役に立てば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker 18.0.9.8 にアップデートがかかってdockerが使えなくなった。

現象

Ubuntu18.04でdocker-ceをインストールして使っていました。
以前は平気で使えていたdockerが急に

docker ps
> Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

と言い出しました。

Qiitaのこの記事やいろんな記事を参考にしたのですが、解決しませんでした。

解決へ (ダウングレード)

そもそも何が起きたのか/var/log/dpkg.logを見ると、数日前にdocker-ce:amd64 5:18.09.8~3-0~ubuntu-bionicにアップロードされたことがわかりました。
いろいろ調べても治らないので、
このgithubのissueを参考に、dockerのバージョンをダウングレードしました。
[Ubuntu] apt-get まとめを参考に、
sudo apt-cache policy docker-ceでインストール可能なdockerのバージョンが出てきます。
sudo apt install docker-ce=5:18.09.1~3-0~ubuntu-bionicとしてやってガイドに乗っていくと直りました。(Ubuntu 18.04 を使っているのでgithubのxenialをbionicに変えました。)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【k8s】Kubernetesやってみた【minikube】

004.png

kubernetesを触ってみたのでまとめてみました

目次

  1. 環境
  2. kubernetesについて
  3. minikube導入
  4. minikube起動
  5. ダッシュボードの起動
  6. サービスを作成してみる
  7. 後片付け
  8. 「Version string empty」エラーについて
  9. まとめ

環境

  • MacBook Pro (Retina, 15-inch, Mid 2015)

kubernetesについて

kubernetesというのは「コンテナを運用しやすくするオープンソースなプラットフォーム」です。
最近よく耳にするkubernetesですが、色々な環境があるんですねー。

よく耳にするものですと「minikube」でしょうか。
こちらは手元のローカル環境で動作させやすいkubernetesで、冗長性の担保はされてないですが動作が軽快だそうです。
minikubeのように手軽に試せる環境として「micro-k8s」、Iot(ラズパイなど)用のさらに軽量な「k3s」があります。

クラウド上のKubernetesとして、「GKS(Googleさん)」、「ACS(Microsoftさん)」、「EKS(Amazonさん)」が提供されており、共通の特徴としてWebGUIでコンテナを管理できます。

Macユーザーだと「Docker for Mac」を利用している方が多いのではないでしょうか。
「Docker for Mac」では設定を行うことでkubernetes環境が利用できます。

001.png
002.png

minikube導入

minikubeを利用してkubeってみましょう。過去に導入したものなので当時の導入手順は覚えてません。
がしかし、brew listコマンドで結果が返ってくるので恐らくbrewコマンドで導入したのだと思います。
うろ覚え申し訳ないです。

$ brew list  | grep kube
kubernetes-cli

$ brew cask list  | grep kube
minikube

下記リンクの手順で導入できるかと思います。

minikube起動

VMにvirtualBoxを指定してminikube起動

$ minikube start --vm-driver=virtualbox

$ minikube status

ダッシュボードの起動

# 下記コマンドでダッシュボード起動(ブラウザが開きます)
# minikubeのダッシュボードはターミナルで「Ctrl+c」で停止できます
$ minikube dashboard
$ kubectl run hello-minikube --image=k8s.gcr.io/echoserver:1.10 --port=8080

「hello-minikube」を起動するコマンドを実行し、ブラウザにてダッシュボードのリロードを行うと「hello-minikube」のPodなどが追加されているのがわかりますね。

003.gif

サービスを作成してみる

# 「hello-minikube」を外部アドレスから参照できるようにする
$ kubectl expose deployment hello-minikube --type=NodePort
## 各種情報を確認してみる(ダッシュボードと同じ情報が出力されます)
$ kubectl get services
$ kubectl get pod
$ kubectl get deployments

後片付け

ダッシュボードで作業しても良いですが、せっかくなのでコマンドでお掃除してみましょう。

# サービスの削除
$ kubectl delete services hello-minikube

# デプロイの削除
$ kubectl delete deployment hello-minikube

# minikubeの停止
$ minikube stop

「Version string empty」エラーについて

minikube startした際にエラーが出ますが、issueを見た感じだと、バグのようです。
とりあえずは正常に動作するようなのでそのまま進めます。 ←エラー出るの気持ち悪いので詳しい方いましたらご指摘ください

$ minikube start
~~中略~~
E0710 15:47:42.634326   85156 start.go:210] Error parsing version semver:  Version string empty
~~中略~~
Everything looks great. Please enjoy minikube!

まとめ

今回は触りの部分だけ実践しましたが、やはり学習コストが高い印象。。。Dockerは割と取っ付きやすかったが。。。
慣れて管理工数が減れば両手を挙げて喜べますが、本番運用への道のりは長くなりそうですw

次回の記事ではymlファイルなどを定義して色々やってみようと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】プロジェクト新規作成から自動テスト/ビルド/デプロイ実現まで

TL;DR

git branchに変更が加わった際、自動で

  • JUnit test (with MySQL)
  • docker build
  • Kubernetes環境にデプロイ

が行われるJavaプロジェクトを完全にゼロから構築します。

登場するもの

OSS

  • Maven
  • MySQL
  • Docker

サービス

  • GitHub
  • CircleCI
  • AWS (ECR, EKS) ⇦ 微修正でその他マネージドk8sにも応用可能かと思います。

サンプルプロジェクトの実装

最終的にディレクトリ構成はこんな感じになります。順を追って作っていきます。
GitHubからcloneして頂いても結構です。

testproject/
    ├ src/
    │   ├ main/
    │   │   └ java/
    │   │        └testpackage/
    │   │            └Main.java
    │   └ test/
    │       └ java/
    │           └testpackage/  
    │              └MainTest.java   
    ├ .cifcleci/
    │   └ config.yml
    ├ schema.sql
    ├ pom.xml
    ├ deploy.yaml
    └ Dockerfile

1. スキーマ定義

テーブルスキーマを記述します。resourceフォルダに置いても良いのですが、今回はトップディレクトリに配置することにします。

データベース名は指定しません。

schema.sql
CREATE TABLE user (id int, name varchar(10));

2. mavenプロジェクト作成

先ほどのtableに適当なレコードを挿入する最小限のJavaプロジェクトを実装します。

JDBC、JUnit、maven-assembly-pluginを使用します。

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>aaaanwz</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1</version>
    <name>testproject</name>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- JDBC driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <!-- JUnit -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.3.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- JUnit test -->
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M3</version>
            </plugin>
            <!-- Build runnable jar -->
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>testpackage.Main</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

1レコード挿入するだけのMainクラスを実装します。

データベースへの接続情報は環境変数から取得します。

src/main/java/testpackage/Main.java
package testpackage;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Main {

  public static void main(String[] args) throws ClassNotFoundException, SQLException {
    final String host = System.getenv("DB_HOST");
    final String dbname = System.getenv("DB_NAME");
    execute(host, dbname);
  }

  static void execute(String host, String dbname) throws ClassNotFoundException, SQLException {
    Class.forName("com.mysql.cj.jdbc.Driver");
    Connection conn = DriverManager.getConnection(
        "jdbc:mySql://" + host + "/" + dbname + "?useSSL=false", "root", "");
    PreparedStatement stmt = conn.prepareStatement("INSERT INTO user(id,name) VALUES(?, ?)");
    stmt.setInt(1, 1);
    stmt.setString(2, "Yamada");
    stmt.executeUpdate();
  }

}

レコードが挿入された事を確認するだけのテストを書きます。

src/test/java/testpackage/MainTest.java
package testpackage;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import testpackage.Main;

class MainTest {
  Statement stmt;

  @BeforeEach
  void before() throws ClassNotFoundException, SQLException {
    Class.forName("com.mysql.cj.jdbc.Driver");
    Connection conn =
        DriverManager.getConnection("jdbc:mySql://localhost/test?useSSL=false", "root", "");
    stmt = conn.createStatement();
  }

  @AfterEach
  void after() throws SQLException {
    stmt.executeUpdate("TRUNCATE TABLE user");
  }

  @Test
  void test() throws Exception {
    Main.execute("localhost", "test");
    try (ResultSet rs = stmt.executeQuery("SELECT * FROM user WHERE id = 1;")) {
      if (rs.next()) {
        assertEquals("Yamada", rs.getString("name"));
      } else {
        fail();
      }
    }
  }
}

3. Dockerfile作成

Dockerfileを書きます。テストは docker buildとは別のステップで行う予定のため、-DskipTestsを付与してビルド時のテストをスキップします。

イメージサイズ削減のためmaven:3.6でビルド、openjdk11:apline-slimで実行するマルチステージビルドを行います。
maven:3.6では約800MB、openjdk11:alpine-slimでは約300MBとなります。現時点でECRの無料枠は500MBのため、個人開発では大きな差です。

Dockerfile
FROM maven:3.6 AS build

ADD . /var/tmp/testproject/
WORKDIR /var/tmp/testproject/
RUN mvn -DskipTests package

FROM adoptopenjdk/openjdk11:alpine-slim

COPY --from=build /var/tmp/testproject/target/test-0.0.1-jar-with-dependencies.jar /usr/local/
CMD java -jar /usr/local/test-0.0.1-jar-with-dependencies.jar.jar

4. k8s yamlファイル作成

3.でビルドされたコンテナをk8sにデプロイするためのyamlを書きます。今回のプログラムは単発でSQLを実行して終了するため、kind: Jobにしてみます。Docker registryのurlは適宜置換してください。

envでDBへの接続情報を定義します。 DB_HOSTの値が mysqlとなっているのは、KubernetesのService経由で接続するためです。

k8s-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  template:
    spec:
      containers:
      - name: test
        image: your-docker-registry-url/testimage:latest
        imagePullPolicy: Always
        env:
        - name: DB_HOST
          value: "mysql"
        - name: DB_NAME
          value: "ekstest"
      restartPolicy: Never
  backoffLimit: 0

5. circleci configファイル作成

本稿のキモです。CircleCIで自動テスト/ビルドを行うための構成設定を書きます。

.circleci/config.yml
version: 2.1
orbs:
  aws-ecr: circleci/aws-ecr@6.1.0
  aws-eks: circleci/aws-eks@0.2.1
  kubernetes: circleci/kubernetes@0.3.0
jobs:
  test: # ①JUnit テストの実行
    docker:
      - image: circleci/openjdk:11
      - image: circleci/mysql:5.7
        environment:
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          MYSQL_DATABASE: test
        command: [--character-set-server=utf8, --collation-server=utf8_general_ci, --default-storage-engine=innodb]
    steps:
      - checkout
      - run:
          name: Waiting for MySQL to be ready
          command: dockerize -wait tcp://localhost:3306 -timeout 1m
      - run:
          name: Install MySQL CLI; Create table;
          command: sudo apt-get install default-mysql-client && mysql -h 127.0.0.1 -uroot test < schema.sql
      - restore_cache:
          key: circleci-test-{{ checksum "pom.xml" }}
      - run: mvn dependency:go-offline
      - save_cache:
          paths:
            - ~/.m2
          key: circleci-test-{{ checksum "pom.xml" }}
      - run: mvn test
      - store_test_results:
          path: target/surefire-reports
  deploy: # ③EKSへのkubectl apply
    executor: aws-eks/python3
    steps:
      - checkout
      - kubernetes/install
      - aws-eks/update-kubeconfig-with-authenticator:
          cluster-name: test-cluster
          aws-region: "${AWS_REGION}"
      - run:
          command: |
            kubectl apply -f k8s-job.yaml
          name: apply
workflows:
  test-and-deploy:
    jobs: 
      - test: # ①JUnit テストの実行
          filters:
            branches:
              only: develop
      - aws-ecr/build-and-push-image: # ②コンテナのビルドとECRへのpush
          filters:
            branches:
              only: master
          create-repo: true
          repo: "testimage"
          tag: "latest"
      - deploy: # ③EKSへのkubectl apply
          requires:
            - aws-ecr/build-and-push-image

①JUnitテストの実行

filterによって、developブランチに変更が加わった際に mvn testが実行されるようにしてみました。この際テスト用MySQLインスタンスが立ち上がり、 testデータベースが準備されます。

公式ドキュメントで詳しく解説されています。  
- Language Guide: Java
- Database Configuration Examples

②コンテナのビルドとECRへのpush

masterブランチに変更が加わった際に、Dockerfileに従ってbuildし、ECRにpushします。

Orbクイックスタートガイドで詳しく解説されています。

③EKSへのkubectl apply

②が実施された後、4.で定義したJobを実行します。

circleci/aws-eksに解説がありますが、サンプルコードをよりシンプルに変更しました。

@0.2.1のドキュメントによるとパラメータaws-regionはRequiredとなっていませんが、実際は必須のようです。ECRのpushで環境変数AWS_REGIONを要求されているので、これをそのまま使いました。

インフラ設定

ほとんど公式ドキュメントへのリンク集です。

1. ECR, EKS環境準備

1-1. 基本設定

test-clusterを立ち上げます。
- Getting Started with Amazon EKS
- Setting Up with Amazon ECR

1-2. EKS上にMySQLをデプロイ

Kubernetes公式にDeploy MySQLというドキュメントが用意されています。

kubectl exec -it mysql-0 mysqlコマンドからekstestデータベースとuserテーブルを用意します。

2. CircleCI projectの設定

2-1. プロジェクトのセットアップ

2-2. 環境変数の設定

  • circleci/aws-ecrでRequiredとなっている環境変数をCircleCI Projectに設定します。
    Roleに要求される権限の詳細は割愛します。

まとめ

  • develop branchにpush
     mvn testが実行され、テストレポートがCircleCIのTest summaryに表示されます。
  • master branchにpush
    ECRにdocker imageがpushされ、EKSでJobが開始します。EKS上のMySQLに id:1 name:Yamadaレコードが挿入されます。

いかがでしたでしょうか。テストをわざと落とす等色々試してみて頂ければと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AmazonLinux2のdockerイメージにpythonをインストールしてAWS ECRにアップする方法

AWS環境を利用している環境において、CodePipeline/CodeBuild/CodeDeploy/CodeCommitを使用している方々、多くいらっしゃると思いますが、CodeBuildで使用するDockerイメージをどこで管理するかという課題に関して記述していければと思います。

Docker-hubで管理してもいいけどAWSで一元管理したい、Docker hub側のサイトでトラブルが起きてアクセスできなくなるのは困る、Docker hubのアカウントを取得して管理するのが面倒などあるかと思いましたので、データ分析基盤のDevOpsの一環で実施した内容を記述します。

  • 環境及び前提

    • 実行環境

      VirtualBox (VM)
      OS:AmazonLinux2
      docker:18.06.1-ce
      pyenv:1.2.13
      Python:3.6.5

      VirtualBoxでAmazonLinux2のboxを作成し、amazon-linux-extrasでdockerをインストールして実施しています。
      ECRのリージョンは東京リージョンで実施しています。

  • 最終ゴール
    CI/CDでCodeBuildを使用する際の、AWSECR内でdockerイメージの管理

Dockerイメージ作成準備

Dockerファイルで設定を記述した後、pythonのパッケージをインストールするための準備をします。

Dockerファイルの作成

Dockerファイル内では必要なパッケージのインストールおよび、pyenvのダウンロード、pythonのインストール、環境変数の設定を実施しています。

今回作成するイメージの基となるイメージはdockerhubのオフィシャルイメージから持ってきています。
https://hub.docker.com/_/amazonlinux

以下がDockerファイルの中身

DockerFile
FROM amazonlinux:2
ADD . .

SHELL ["/bin/bash", "-c"]
RUN yum update -y
RUN yum install -y gcc bzip2 bzip2-devel openssl openssl-devel readline readline-devel git wget gcc-c++ unixODBC-devel tar.x86_64

RUN echo 'export PYENV_ROOT="/usr/local/pyenv"' | tee -a /etc/profile.d/pyenv.sh
RUN echo 'export PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${PATH}"' | tee -a /etc/profile.d/pyenv.sh
RUN echo 'eval "$(pyenv init -)"' | tee -a /etc/profile.d/pyenv.sh

RUN git clone https://github.com/pyenv/pyenv.git /usr/local/pyenv
RUN source /etc/profile.d/pyenv.sh && pyenv install -v 3.6.5 && pyenv global 3.6.5 && pip install --upgrade pip==19.0.3 && pip install -r requirements.txt && pip install awscli

今回の環境はsshでログインするユーザにかかわらずデフォルトのpython2.7系ではなく、python3.6.5を利用できるようにprofile.dのpyenv.shでパスを管理しています。

requirements.txtの作成

pipでインストールしたいパッケージとそのバージョンを記載します。
既存の環境があるなら以下のコマンドを実行しインストールするパッケージの一覧を取得してください。

pip freeze > requirements.txt 

既存の環境がない場合は、自作してください。

AWS ECRの設定

AWSコンソール上でECRにdockerイメージをpushできる環境を構築します。

リポジトリの作成

AWSコンソール画面にログインし、ECRサービスに遷移します。
そしてリポジトリを作成します。
今回はリポジトリ名を「python3.6.5」としています。

IAMでECRへの適切な権限が与えられているユーザを用いる必要があります。

ECRのPermissionsの設定

以下はイメージをダウンロードする際に必要な設定です。
Permissions画面へ遷移し、以下のアカウントIDの部分を編集してJsonを貼り付けます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CodeBuildAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::アカウントID:root"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ]
    }
  ]
}

ECRへのイメージpush

ECRにログインし、dockerイメージをbuild後、実際にpushします。
以下アカウントID部分を修正して利用してください。

$(aws ecr get-login --no-include-email)
docker build -t アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/python3.6.5:latest .
docker push アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/python3.6.5:latest

注意点

  • dockerにログインする必要はありません。
  • コマンドを使用するOSにAWS CLIをインストールしている必要があります。
  • aws configureに指定しているaccesskeyに紐づくユーザは、ECRの利用をIAMで許可されている必要があります。
  • dockerにpushできない場合はセッションが切れている場合があるので、もう一度$(aws ecr get-login --no-include-email)を実行する必要があります。

まとめ

ECRで管理すればセキュリティも担保できる上に、CodeBuildからイメージをダウンロードする際の可用性が上昇するという印象でした。
特に難しいこともないので、是非試してみてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vagrant環境のDockerで、Zabbixサーバとエージェントを構築する

イントロ

以前自分のWikiに「Vagrant環境のDockerサーバに、Zabbixのサーバとエージェントを構築する」って記事を書いたのですが、そのときはVagrantのProvision機能でDockerをチマチマ実行してました。

今回は同じ環境を docker-compose で作成します。

作成する環境

  • 1つのVagrantfileで Zabbixサーバを1つ、別のVagrantfileで、監視されるエージェント側のOSを二つ構築します。
  • ZabbixサーバはUbuntu Linux 上のDocker上に構築します。
  • エージェント側もUbuntu Linuxとします。
  • それぞれの仮想マシンはネットワーク的に到達可能である必要がありますが、Vagrantはデフォルトではおなじネットワークを共有しないようなので1、ウラLANとして 192.168.33.0/24 のネットワークを構築します。
  • Zabbixサーバは80番ポートでWEBサーバが起動しますが、VagrantはNATかけないとアクセス出来ないので、port forwardingで 8888番ポートアクセスを80番ポートへ転送します。

図にするとこんな感じ。
Vagrant_Docker_zabbix.png

ちなみに今回作業する環境は下記の通り。

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.5
BuildVersion:   18F132
$

Zabbixのバージョンは、日本語化の手順がエラーになる場合があるようで、 ubuntu-4.0.7 を指定しています。

コードの取得

使用するファイル群をGitHubから取得します。

$ git clone https://github.com/masatomix/environment_template.git
$ cd environment_template/
$ git checkout -t origin/feature/for_qiita_zabbix

Zabbixサーバの構築

サーバの構築はVagrantで一発です。

$ vagrant up

と実行することで、Ubuntu Linuxの構築から Dockerのインストール、Dockerサーバ上でのZabbixサーバのインストール、そのサーバ自体を監視するためのZabbixエージェントのコンテナのインストール、と設定と起動、までが行われます。

Vagrantが動いてるOS上のブラウザからhttp://127.0.0.1:8888/ へアクセスして、Zabbixサーバのログイン画面が表示されればOKです。admin/zabbix で入れることを確認しておきましょう。
top.png

ちなみにVagrantfile などはこんな

cloneした内容を見ればイイのですが、抜粋。

Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.network "forwarded_port", guest: 80, host: 8888
  config.vm.network "private_network", ip: "192.168.33.10"

  # コレを行わないと
  # http://www.masatom.in/pukiwiki/Vagrant/TIPS%BD%B8/#ab1dd863
  # vagrant packageでexportしたBoxが正しく動かないため記述
  config.vm.provider "virtualbox" do |vb|
    vb.customize [ "modifyvm", :id, "--uartmode1", "disconnected", "--memory", 4096 ]
  end

  config.vm.provision :shell, :path => "./script/provision_init.sh",:privileged => false
  config.vm.provision :shell, :path => "./script/provision_ja.sh",:privileged => false

  config.vm.provision :shell, :path => "./script/provision_docker.sh",:privileged   => false
  config.vm.provision :shell, :path => "./script/provision_docker_zabbix.sh",:privileged   => false
end
provision_docker_zabbix.sh
#!/bin/sh

cd /vagrant/zabbix
sudo docker-compose up -d --build

docker-compose.yml はこちら

Docker上にZabbixサーバを構築するときにうごいた docker-compose.yml はこちらです。

docker-compose.yml
version: '3.5'
services:

  mysql-server:
    image: mysql:5.7
    command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']
    environment:
      - MYSQL_DATABASE=${DB_DATABASE}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./db/mysql_data:/var/lib/mysql
    user: "1000:50" # remove at Photon
    restart: always

  zabbix-java-gateway:
    image: zabbix/zabbix-java-gateway:${VERSION}
    volumes:
      - /etc/localtime:/etc/localtime:ro
    restart: always

  zabbix-server-mysql:
    image: zabbix/zabbix-server-mysql:${VERSION}
    depends_on:
      - mysql-server
      - zabbix-java-gateway
    environment:
      - DB_SERVER_HOST=mysql-server
      - MYSQL_DATABASE=${DB_DATABASE}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
    volumes:
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 10051:10051
    restart: always

  zabbix-web-nginx-mysql:
    build: ./nginx/
    depends_on:
      - mysql-server
      - zabbix-server-mysql
      - zabbix-java-gateway
    environment:
      - DB_SERVER_HOST=mysql-server
      - MYSQL_DATABASE=${DB_DATABASE}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
      - ZBX_SERVER_HOST=zabbix-server
      - PHP_TZ="Asia/Tokyo"
    volumes:
      - /etc/localtime:/etc/localtime:ro
    links:
      - zabbix-server-mysql:zabbix-server
    ports:
      - 80:80
    restart: always

  zabbix-agent:
    image: zabbix/zabbix-agent:${VERSION}
    links:
      - zabbix-server-mysql:zabbix-server
    volumes:
      - /etc/localtime:/etc/localtime:ro
    restart: always
.env
VERSION=ubuntu-4.0.7

DB_DATABASE=zabbix
DB_USER=zabbix
DB_PASSWORD=zabbix
DB_ROOT_PASSWORD=zabbix

構築している内容は 以前記事にした モノとほとんど同じなので、細かい説明は省略します。

Zabbixエージェントの構築

つづいてエージェント側。

$ cd agent
$ vagrant up

と実行することで、Ubuntu Linuxの構築から Zabbixエージェントのインストールと設定と起動、までが行われます。

vagrant up が完了したらOSが二つ立ち上がっているはずので、ログイン出来ることを確認しておきましょう。

$ vagrant ssh agent001 (agent002)
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-139-generic x86_64)
...
vagrant@agent001:~$

ちなみにVagrantfile などはこんな

cloneした内容を見ればイイのですが、抜粋。

agent/Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"

  config.vm.define :agent001 do | agent001 |
    agent001.vm.hostname = "agent001"
    agent001.vm.network :private_network, ip: "192.168.33.11"
    agent001.vm.provision :shell, :path => "./script/provision.sh",:privileged   => true
  end

  config.vm.define :agent002 do | agent002 |
    agent002.vm.hostname = "agent002"
    agent002.vm.network :private_network, ip: "192.168.33.12"
    agent002.vm.provision :shell, :path => "./script/provision.sh",:privileged   => true
  end
end

Zabbix Server自体の監視開始

ブラウザからZabbixの環境設定をおこないます。
http://127.0.0.1:8888/ へアクセスし、admin/zabbix でログイン します。

あ、まずは右上のヒトのアイコンをクリックして、LanguageをJapaneseにしておきます。

さて、まずはZabbix サーバ自体の監視を行います。
設定 >> ホスト >> Zabbix server で、DNS名に「zabbix-agent」と入力、接続方法を「DNS」へ変更し、更新をクリックします2
hosts001.png

上記の通り、ほどなくして「ZBX」のアイコンが緑になっていればOKです。

各OSのエージェントでの監視開始(自動登録)

続いて、各OS agent001/agent002 の監視設定を追加します。元の記事 では手動登録していますが、同じようにやってもおもしろくないので、今回はディスカバリ機能を用いた自動登録を行ってみます。

手順はこんな感じ。

  • 設定 >> ディスカバリ の画面で、特定のローカルネット上の Zabbixエージェントを定期的に検索する設定を追加。そのときに、system.uname の値を取得するようにしておく
  • 設定 >> アクション の画面で、さきの検索にヒットした エージェントのうち、登録したいエージェントをフィルタする設定を記述
  • 設定 >> アクション >> 実行内容 で、ホストを追加したり、それをホストグループに入れたり、テンプレートをリンクしたりなど、実行したい処理を記述。

という流れになるようです。

ディスカバリルールの作成

設定>>ディスカバリで「ディスカバリルールの作成」を選択
01.png

名前に「My Local Network」、IPアドレスの範囲を今回設定した「192.168.33.1-20」くらいに設定、監視間隔を一旦60sに(たぶん有効なはず)。またチェックの欄の「新規」をクリック。
02.png

チェックのタイプを指定出来るので「Zabbixエージェント」を選択
03.png

キーに「system.uname」を選択して、「追加」をクリックします。
04.png

追加されました。最後に全体の「追加」ボタンを押せば完了です。
05.png

ディスカバリルールが作成できました。
06.png

監視データ >> ディスカバリ に遷移してみると、条件に合致したエージェント(192.168.33.11,12)が発見されていることが確認できるとおもいます。
07.png

ちなみに system.uname って。

途中ででてきた、チェックのキーとして設定したsystem.uname についてですが、ここにはZabbixがエージェントから取得できるデータ名を指定することが出来るようで、たとえばsystem.uname は下記のコマンドの実行結果となります。

(Server側のUbuntuで)
vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose exec zabbix-server-mysql zabbix_get -s zabbix-agent  -k system.uname
Linux fdd3e6a15327 4.4.0-139-generic #165-Ubuntu SMP Wed Oct 24 10:58:50 UTC 2018 x86_64

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose exec zabbix-server-mysql zabbix_get -s 192.168.33.11  -k system.uname
Linux agent001 4.4.0-139-generic #165-Ubuntu SMP Wed Oct 24 10:58:50 UTC 2018 x86_64

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose exec zabbix-server-mysql zabbix_get -s 192.168.33.12  -k system.uname
Linux agent002 4.4.0-139-generic #165-Ubuntu SMP Wed Oct 24 10:58:50 UTC 2018 x86_64

vagrant@ubuntu-xenial:/vagrant/zabbix$

このあとのアクションの設定で「この戻り値(受信した値) に agent00 が含まれていたら」など条件を指定できます。なので、このあとで使用したい値を記載しておく、という感じになります。

アクションの定義

続いて、アクションを定義していきます。
設定 >> アクションに移動し、イベントソースを「ディスカバリ」にして、「アクションの作成」をクリック。
08.png

名前を「Auto discovery (Local Network)」、新規条件を「サービスのタイプ」にして、「Zabbixエージェント」を選択し、追加 をクリック。
09.png

実行条件が追加出来ました。実行条件は複数設定できるので、たとえば「受信した値」に「agent00」を含む3 なんて条件を追加してみましょう。
11.png
追加。
12.png

つづいて「実行内容」を選択します。実行内容は条件に合致するエージェントに対する処理のことで「ホストを追加」「ホストグループに追加」「テンプレートとのリンクを作成」などを実施します。

「実行内容」タブをクリックして「新規」をクリック
13.png

実行内容のタイプ は「ホストを追加」を選んで「追加」
14.png
追加されました。
15.png

また「新規」を選択し「ホストグループに追加」、ホストグループ名に「Discovered hosts」を設定し
17.png
「追加」をクリック。
18.png
追加されました。
19.png

また「新規」を選択し「テンプレートとのリンクを作成」、テンプレートに「linux」などと入れると「Template OS Linux」などと補完候補が出てくるのでそれを選択。
20.png
「追加」をクリックすると、、
21.png

追加されました。最後にボタンの「追加」をクリックすれば、、、
22.png

アクションの登録も完了です。
23.png

設定>>ホスト をしばらく見ていると、、、agent001(192.168.33.11),agent002(192.168.33.12)が追加されましたねー。。。
24.png

ちなみにアクションには他にも、「あのディスカバリルールで検知したエージェントのときだけ」なんて設定も可能です。
25.png

以上で、基本的なZabbixサーバ/Zabbixエージェントの環境構築は完了です。
今回はVagrantでコマンド一発で環境構築をしましたが、オンプレやAWSに構築する場合も基本的に同じコマンドを叩けばOKでしょう。

おつかれさまでした。

おまけ。データのバックアップ

ついでに、MySQLのデータベースのバックアップ手順もまとめておきます。

vagrant sshでZabbix サーバにログイン後、

vagrant@ubuntu-xenial:~$ cd /vagrant/zabbix/

に移動しておきます。

MySQL以外のコンテナの停止

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose ps
                    Name                                  Command               State              Ports
-------------------------------------------------------------------------------------------------------------------
zabbix_mysql-server_1_bbe6d5af81da             docker-entrypoint.sh --cha ...   Up      3306/tcp, 33060/tcp
zabbix_zabbix-agent_1_e8a8079c2325             /sbin/tini -- docker-entry ...   Up      10050/tcp
zabbix_zabbix-java-gateway_1_92505d90c8f9      docker-entrypoint.sh             Up      10052/tcp
zabbix_zabbix-server-mysql_1_e37acaaa644d      /sbin/tini -- docker-entry ...   Up      0.0.0.0:10051->10051/tcp
zabbix_zabbix-web-nginx-mysql_1_432a2d375844   docker-entrypoint.sh             Up      443/tcp, 0.0.0.0:80->80/tcp
vagrant@ubuntu-xenial:/vagrant/zabbix$ 

起動しているコンテナを、docker-compose の機能で停止します。引数はdocker-compose.ymlに書いてある「サービス名」もしくは上記のNameの一部分を使用します。

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose stop zabbix-agent zabbix-java-gateway zabbix-server-mysql zabbix-web-nginx-mysql
Stopping zabbix_zabbix-web-nginx-mysql_1_432a2d375844 ... done
Stopping zabbix_zabbix-agent_1_e8a8079c2325           ... done
Stopping zabbix_zabbix-server-mysql_1_e37acaaa644d    ... done
Stopping zabbix_zabbix-java-gateway_1_92505d90c8f9    ... done

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose ps
                    Name                                  Command                State            Ports
--------------------------------------------------------------------------------------------------------------
zabbix_mysql-server_1_bbe6d5af81da             docker-entrypoint.sh --cha ...   Up         3306/tcp, 33060/tcp
zabbix_zabbix-agent_1_e8a8079c2325             /sbin/tini -- docker-entry ...   Exit 0
zabbix_zabbix-java-gateway_1_92505d90c8f9      docker-entrypoint.sh             Exit 143
zabbix_zabbix-server-mysql_1_e37acaaa644d      /sbin/tini -- docker-entry ...   Exit 0
zabbix_zabbix-web-nginx-mysql_1_432a2d375844   docker-entrypoint.sh             Exit 0


vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
d44071b826a6        mysql:5.7           "docker-entrypoint.s…"   16 minutes ago      Up 16 minutes       3306/tcp, 33060/tcp   zabbix_mysql-server_1_bbe6d5af81da

MySQL以外が停止されました。
以後「MySQL以外のコンテナの停止」といったらこの作業を指すこととしましょう。

データのバックアップ

MySQLコンテナに入って、データをバックアップします。

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose exec mysql-server /bin/bash

I have no name!@d44071b826a6:/$ mysqldump --single-transaction -uzabbix -pzabbix zabbix > /tmp/db20190722.dump
mysqldump: [Warning] Using a password on the command line interface can be insecure.

I have no name!@d44071b826a6:/$ exit
exit

コンテナ内の/tmpにバックアップデータが出力されました。

つづいてコンテナからこのデータを取り出します。

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker cp d44071b826a6:/tmp/db20190722.dump ./
vagrant@ubuntu-xenial:/vagrant/zabbix$ ls -lrt
合計 2736
drwxr-xr-x 1 vagrant vagrant      96  7月 22 00:07 nginx
drwxr-xr-x 1 vagrant vagrant      96  7月 22 00:07 db
-rw-r--r-- 1 vagrant vagrant    2091  7月 22 00:07 docker-compose.yml
-rw-r--r-- 1 vagrant vagrant 2796867  7月 22 00:35 db20190722.dump  <- コレ
vagrant@ubuntu-xenial:/vagrant/zabbix$

コンテナからの取り出しが完了しました。dumpによるフルバックアップは、このデータを保管しておけばOKです。
最後に各サーバを起動して、バックアップは完了です。

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose start zabbix-agent zabbix-java-gateway zabbix-server-mysql zabbix-web-nginx-mysql
Starting zabbix-java-gateway    ... done
Starting zabbix-server-mysql    ... done
Starting zabbix-web-nginx-mysql ... done
Starting zabbix-agent           ... done

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose ps
                    Name                                  Command               State              Ports
-------------------------------------------------------------------------------------------------------------------
zabbix_mysql-server_1_bbe6d5af81da             docker-entrypoint.sh --cha ...   Up      3306/tcp, 33060/tcp
zabbix_zabbix-agent_1_e8a8079c2325             /sbin/tini -- docker-entry ...   Up      10050/tcp
zabbix_zabbix-java-gateway_1_92505d90c8f9      docker-entrypoint.sh             Up      10052/tcp
zabbix_zabbix-server-mysql_1_e37acaaa644d      /sbin/tini -- docker-entry ...   Up      0.0.0.0:10051->10051/tcp
zabbix_zabbix-web-nginx-mysql_1_432a2d375844   docker-entrypoint.sh             Up      443/tcp, 0.0.0.0:80->80/tcp
vagrant@ubuntu-xenial:/vagrant/zabbix$

起動されました。以後「各サーバを起動」といったらこの作業を指すこととしましょう。

おまけ。データのリストア

コンテナ停止

既出の手順「MySQL以外のコンテナの停止」を実施します。

リストア準備

さてMySQL以外が停止している状態で、リストアを開始します。手順は、すでに存在するデータベースを削除したのち、事前に取得しておいたバックアップデータを戻すという流れです。

まずはMySQLコンテナにバックアップデータをコピーします。

vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker cp ./db20190722.dump d44071b826a6:/
vagrant@ubuntu-xenial:/vagrant/zabbix$ sudo docker-compose exec mysql-server /bin/bash

I have no name!@d44071b826a6:/$ ls -lrt
total 2800
...
-rw-r--r--   1 1000 1000 2796867 Jul 22 00:35 db20190722.dump
I have no name!@d44071b826a6:/$

コンテナへデータを転送出来ました。

DB削除・空DB作成・リストア

I have no name!@d44071b826a6:/$  mysql -uzabbix -pzabbix
...
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>  drop database zabbix;
Query OK, 144 rows affected (1.70 sec)

mysql> create  database zabbix;
Query OK, 1 row affected (0.01 sec)

mysql> exit
Bye

さて、データを入れていきます。

I have no name!@d44071b826a6:/$ mysql -uzabbix -pzabbix zabbix < ./db20190722.dump
mysql: [Warning] Using a password on the command line interface can be insecure.
I have no name!@d44071b826a6:/$


I have no name!@d44071b826a6:/$ exit
exit

リストア完了です。

起動

最後に「各サーバを起動」しましょう。おつかれさまでした!

関連リンク


  1. publicにBridgeすりゃイイんですが 

  2. Zabbixサーバ自体にインストールされたエージェントのコンテナは、「zabbix-agent」で名前解決される 

  3. 受信した値ってのは、system.unameのことで、ココにはホスト名(agent001,agent002など)が含まれているんでしたよね。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【2019年7月版】Hyperledger Indy のサンプル(ちょい古め)を動かしてみた

前回ビルドに挑戦したHyperledger Indyですが引き続き動作確認を行ってまいります。というか、ユースケースがいまいちピンと来ないので、懲りずに古いサンプルを動かしてみました。

紆余曲折ありましたがなんとか動いたので手順などの解説をいたします。(めちゃくちゃ大変だった。)

まず、修正済みのソースはこちらです。
手っ取り早く動かしたい方、DockerインストールしたUbuntuで上記リポジトリをcloneしてReadmeの手順に従っていただければOKです!

以下では通常の動作手順について、順を追って解説します。

1. コンテナのビルド

まず、Rustでのindyソースをコンテナ内でビルドして、デモに必要な各種のコンテナを作成します。

こちらの修正済みのプロジェクト からソースをクローンしておきます。以下では、~/indy-ssivc-tutorialにクローン済みとして説明いたします。

また、docker コマンドは sudo 付きで動かす環境であるとして説明します。

1-1. indy コンテナのビルド

以下のコマンドで、indy 本体のネットワークを構成する docker コンテナをビルドします。

$ cd ~/indy-ssivc-tutorial/von-network
$ sudo ./manage build

1-2. API コンテナのビルド

以下のコマンドで indy とアクセスする API や管理ツールなどのコンテナ群をビルドします。

$ cd ~/indy-ssivc-tutorial/TheOrgBook/docker
$ sudo ./manage.sh build

1-3. デモアプリコンテナのビルド

以下のコマンドで indy のデモを行う Web アプリ用のコンテナ群をビルドします。

$ cd ~/indy-ssivc-tutorial/permitify/docker
$ sudo ./manage build

このあたりになるとディスクスペースやメモリなど逼迫してくるかもしれません。不要な docker イメージは削除して軽くしておいたほうがいいかもしれません。

2. 起動

無事に docker コンテナがビルドできたら同様の順番でコンテナを起動していきます。

2-1. indy ネットワークの起動

以下のコマンドで indy のテストネットワークを起動します。

$ cd ~/indy-ssivc-tutorial/von-network
$ sudo ./manage start

これでindy用のコンテナがいくつか起動します。

2-2. API コンテナ群の起動

続いて indy に直接接続する API 用のコンテナ群を起動します。
新しいコンソールを開き

$ cd ~/indy-ssivc-tutorial/TheOrgBook/docker
$ sudo ./manage.sh start

で、API用のコンテナがいくつか起動します。

2-2-1. 起動するサイト・サービス

この時点でいくつかのサイトが立ち上がります。

Solrはまぁ、おまけみたいなものです。

2-3. デモアプリコンテナ群の起動

以下のコマンドでデモアプリ用のコンテナ群を起動します。
新しいコンソールを開き

$ cd ~/indy-ssivc-tutorial/permitify/docker
$ sudo ./manage start all APPLICATION_URL=http://192.168.1.10 THE_ORG_BOOK_APP_URL=http://192.168.1.10:8080

で、OKです。

ここで重要なのが、APPLICATION_URLで渡しているのが、デモアプリ用のコンテナ群が立ち上がるホストのIPアドレス、THE_ORG_BOOK_APP_URLで渡しているのが、上記のAPI用コンテナ群が立ち上がるホストのアドレス(ポート番号込み)です。
今回は1台のDockerホスト上で全てのコンテナを動かすので同一のIPアドレスとなっています。
また、この変数を設定せずに単に ./manage start all と実行した場合は、ローカルホストからのみのアクセス が有効になります。

2-3-1. 起動するサイト・サービス

ここでデモ用のサイト群がわーっと立ち上がります。

上記の手順で APPLICATION_URL を使用している場合は、localhostの代わりにそのIPアドレスでアクセス可能です。

3. コンテナの停止

各コンソールで Ctrl+C でプロセスを落とせば Graceful Shutdown となります。

4. 使用済みの container と volume の削除

前回の記事でも注意として記載しましたが、indyはブロックチェーンのプロダクトでありますので一度、動かしてブロックが生成されてしまうと後戻りができません
テストネットを止めて再起動、ということが簡単にできませんので、デモサイトを落とした後はこの削除の手順が必須です。

4-1. indy 用コンテナの削除

以下のコマンドで削除を行います。

$ cd ~/indy-ssivc-tutorial/von-network
$ sudo ./manage rm

4-2. API用コンテナの削除

同様に以下のコマンドで使用済みコンテナの削除を行います。

$ cd ~/indy-ssivc-tutorial/TheOrgBook/docker
$ sudo ./manage.sh rm

4-3. デモサイト用コンテナの削除

同様に以下の手順で削除します。

$ cd ~/indy-ssivc-tutorial/permitify/docker
$ sudo ./manage rm

基本的な動作方法は以上です。

4-4. 動かし方

実際のデモサイトのアクセス方法などはこちらをご覧ください

また、ここでどんなことを実現したいのか?については以下の記事でわかりやすく解説していただいてます。

これらのデモサイトでどんなことができるのか、できるようにしたいのか、はお分かりいただけたかと思います。

5. どうやって動かしたのか

ここからが一応の本題です。このちょい古めのサンプルは、最新の Rust ではコンパイルが通りません。
また、API用サーバーやデモサイトなどのコードが大量にあるため、libindy を最新のものにしてコンパイル通ればオK☆、なんてことにはなりません。
当時の AS IS で動作確認が必要なのであります。
そんなわけで今回の古めのサンプル(といっても一昨年だけど。。。)をちゃんと動作させるに当たって、どうやって手当てをしたか、について述べていきたいと思います。

1. Rustのビルド

まず、もっとも困難だったのが どのバージョンのRustならビルドが通るのか、そして同時に 全体がよろしく収まってくれるかです。上記でも述べましたが各種パッケージを最新にすれば現状のRustでビルドが通るのは前回のトライで確認済みです。しかし、参照するコードが大量にあるためコア部分のみバージョンアップする、なんてことはとてもできないのです。

というわけで、当時の libindy はどうやってビルドしていたの?をどうやって調べたか、ですが、まず cargo のパッケージを調べました。

以下が、例えばですが、indy 1.6.7 の登録情報です。
https://crates.io/crates/indy/1.6.7
当たり前ですがちゃんとビルドされてcargoに登録されています。・・・どうやって?
でも、単にビルドして、アップロードしてるわけじゃないよね・・・?
たぶん jenkins か circle-ci とかでUTは通してるはずでしょう・・・というわけで・・・

https://github.com/hyperledger/indy-sdk/tree/master/libindy/ci

はい、libindy が ci でテストを実施している流れは ubuntu.dockerfile に書いてあります。そしてlibindyをビルドするrustをインストールする箇所で・・・

ubuntu.dockerfile
...
USER indy

RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.36.0
ENV PATH /home/indy/.cargo/bin:$PATH
...

はい、Rustのバージョン指定してますね!つまり、その当時の ubuntu.dockerfile を見ればいい というわけですね!

そして 当時 とはいつなのか?というと・・・indy-ssivc-tutorial/von-network/Dockerfile に以下の記述があります。

von-network/Dockerfile
...
RUN git clone https://github.com/hyperledger/indy-sdk.git
WORKDIR /home/indy/indy-sdk/libindy
RUN git fetch
RUN git checkout 778a38d92234080bb77c6dd469a8ff298d9b7154
...

この checkout 778a38d92234080bb77c6dd469a8ff298d9b7154 のハッシュ値を github のURLに貼り付けるとコミットログを見ることができます。具体的には以下のURLで確認できます。

https://github.com/hyperledger/indy-sdk/commit/778a38d92234080bb77c6dd469a8ff298d9b7154

6 Mar 2018 のコミットであることが確認できます。この当時の ubuntu.dockerfile を見ればいいというわけですね!いや、大変だった!w

というわけでubuntu.dockerfileのコミットログを確認してみましょう。

https://github.com/hyperledger/indy-sdk/commits/master/libindy/ci/ubuntu.dockerfile

このリストから2018.03.06以前の最新版を探してくればOK、ということになります。
というわけで・・・

https://github.com/hyperledger/indy-sdk/commit/43b5e88e7b8c0ba9f0db600a0366319783760406#diff-6b80b089e2db8e11e1d59adbe01eecf2

この 26 Feb 2018 のコミット近辺の rust のバージョンが分かればいいんですね~というわけで、ubuntu.dockerfile を見てみますと・・・

...
ENV RUST_ARCHIVE=rust-1.21.0-x86_64-unknown-linux-gnu.tar.gz
ENV RUST_DOWNLOAD_URL=https://static.rust-lang.org/dist/$RUST_ARCHIVE
...

上記の定義で 1.21.0 をダウンロードしてますね。。。う~ん、tar.gz をそのままダウンロードしてるのはちょっとなぁ。。。と、次のコミットを確認します。

https://github.com/hyperledger/indy-sdk/commit/b86cd0f1ea4fb0520edb5552c7212998bdc1435d#diff-6b80b089e2db8e11e1d59adbe01eecf2

ここでの ubuntu.dockerfile を見てみますと・・・

...
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.21.0
...

rustup でバージョン指定する方法が書かれてますね!これっぽい!!

いや、実際には 1.21.0 ではダメで、次の "Apr 23, 2018" の "Update rust to 1.25.0." が微妙にダメ(ビルドは通ったけど、サイト動かすとダメ)で、次の "May 30, 2018" の "Increment Rust version to 1.26.0" でうまくいくようになりました。

これで Rust のコンパイルエラーはなくなりました。すでに3日ほど経過してます。

2. 参照パッケージのバージョン

Dockerfile 内で apt installindy_plenum などをインストールしてますが、リポジトリサイトの "deb https://repo.sovrin.org/deb xenial $indy_stream" からご指定のバージョンは既に削除されているのですね・・・

というわけで現在登録されているバージョンの最古のものから順にちゃんとバージョン間の依存性の整合性がとれているものを割と総当たりで試してみました。とは言え、古いもの順ではうまくいく組み合わせはすぐ見つかりました。

結果、indy_plenum_ver=1.2.242indy_node_ver=1.2.301 が適しているようです。

3. tob-web のビルドが通らない

tob-web/package.json に以下のような参照があります。

tob-web/package.json
...
    "localize-router": "git+https://github.com/cywolf/localize-router.git",
...

これは最新版ではコケます。当時の依存関係とは変わっているのですから当然です。(っていうかリポジトリ直接はやめてw)
そして以下の issue を発見しました。

https://github.com/IBM-Blockchain-Identity/indy-ssivc-tutorial/issues/26

やっぱりビルド通らないよね?と思っていたら・・・"バージョン 1.0.1に直したよ" というコメントがあったので、その通りにいたしました。

あら不思議、ビルドが通っちゃう・・・

4. permitify のビルドが通らない。

このIndyのサンプルプログラムは permitify など Django ベースのWebサイトを多数、起動するのですが、Django の起動がうまくいったか失敗したかがぱっと見ではわからないので、ちょっとハマりました。

コンテナではうまくいっているように見えて、コンテナの中に入って psするとpyhton のプロセスもあるけど、ssコマンドで確認するとポートをlistenしていない。。。というわけで manage.py start とかやってみると初めてエラーメッセージがダラーっと出てて来る、そんな状態でした。Pythonプロセスが無駄に生きてるからやっかいなんですよね~。

とりあえず、エラーメッセージが出てくれればもう後はググって対応だけなのでなんとかなりました。

依存関係のバージョンを以下のように修正しただけです。

  • attr : 17.3.0 -> 17.4.0
  • von-agent: 0.5.0 -> 0.5.2

これだけで半日かかってますけど。

5. localhost からしか動作しない

これはだいぶ困りました。実際の手順では http://localhost:8080 のチュートリアルサイトから http://localhsot:500x の各サイトへリンクが表示されています。
そしてそれが localhost 決め打ちなんですね。。。

いや、それはどうなのよ~?とソース(Angular) を見てみましたが、外のAPI(http://localhost:8081)から取得するだけで Angular側では全然、決めていない・・・オーマイ。。。となってしまったわけです。

いろいろ見てみると、docker-compose.ymlで以下のような記述があります。

permitify/docker/docker-compose.yml
...
      TEMPLATE_NAME: faber_college
      THE_ORG_BOOK_API_URL: ${THE_ORG_BOOK_API_URL}
      THE_ORG_BOOK_APP_URL: ${THE_ORG_BOOK_APP_URL}
      APPLICATION_IP: 0.0.0.0
      APPLICATION_PORT: 8080
      APPLICATION_URL: ${APPLICATION_URL}:5006
...

これはなんか、${APPLICATION_URL}は自分のサイトのアドレスで ${THE_ORG_BOOK_APP_URL}http://localhost:8080 に戻る時のURLなんじゃないの?っぽいよね??という勘と、manageスクリプトで

permitify/docker/manage
...
configureEnvironment () {
  for arg in $@; do
    case "$arg" in
      *=*)
        export ${arg}
        ;;
    esac
  done

  export APPLICATION_URL=${APPLICATION_URL-http://localhost}
  # export THE_ORG_BOOK_API_URL=${THE_ORG_BOOK_API_URL-https://django-devex-von-dev.pathfinder.gov.bc.ca/api/v1}
  # export THE_ORG_BOOK_APP_URL=${THE_ORG_BOOK_APP_URL-https://devex-von-dev.pathfinder.gov.bc.ca}
  export THE_ORG_BOOK_API_URL="http://$DOCKERHOST:8081/api/v1"
  export THE_ORG_BOOK_APP_URL="http://$DOCKERHOST:8080"
  export TOB_INDY_SEED=the_org_book_issuer_000000000000
  export LEDGER_URL=http://von-web:8000
}
...

ここで、'=' が含まれていたら exportしているので変数渡せるようにしてくれているんだということと、APPLICATION_URLTHE_ORG_BOOK_APP_URL のアドレスがlocalhostとdockerのhostでlocalhostじゃないとダメな理由がはっきりしましたね。localhostは100歩譲って外から見たIPでも動くと思いますが、Docker hostは完全に docker が動いているホストのdockerネットワーク上のIPアドレスなのでそのマシンから見ないとこのアドレスは解決できないでしょう、ということですね。たぶん。

そんなわけで THE_ORG_BOOK_APP_URLはいきなり$DOCKERHOSTを使わずに、外からちゃんと指定できる余地を残しておけばよいのです。以下のように。

permitify/docker/manage
...
export THE_ORG_BOOK_APP_URL=${THE_ORG_BOOK_APP_URL-http://$DOCKERHOST:8080}
...

で、起動時に外から見えるIPアドレスを教えてあげればOKなわけです。きっと。

$ ./manage start all APPLICATION_URL=http://192.168.1.10 THE_ORG_BOOK_APP_URL=http://192.168.1.10:8080

この指定がうまく動いたので、Indyデモサイトは外部から http://192.168.1.10:8080 でめでたくアクセスできるようになりました。

いったん、以上といたします。いや~長かった。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Raspbian GNU/Linux 10 BusterにDockerをインストールする

ref: https://github.com/docker/for-linux/issues/709

にissueが上がっている通りで2019/07/23時点ではRaspbian busterにdocker-ceはそのままではインストールできない。よって

curl -sSL https://get.docker.com/ | sed 's/"buster"/"stretch"/' | sh

として、busterとしてではなく、stretch用のをインストールすることで回避できる。workaroundなやり方なので正式対応が来たらアップデートしましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む