20190415のdockerに関する記事は18件です。

Docker php:7.3(7.2)-fpm-alpineベースでphp-ast extention導入

個人的にメンテしているdyoshikawa/laravelイメージでPhanを使えるようにしたかった。
php-ast導入が必要だったのでビルド方法の記録。

OGProgrammer/php 7.2 with ast phan argon support

基本的には上記を参考にした。

Dockerfile
RUN git clone https://github.com/nikic/php-ast.git \
    && cd php-ast \
    && phpize \
    && ./configure \
    && make install \
    && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \
    && cd .. && rm -rf php-ast

こんな記述をして docker build を走らせると

Cannot find autoconf. Please check your autoconf installation and the
$PHP_AUTOCONF environment variable. Then, rerun this script.

エラー。

PECL::memcacheインストールしようとしたらphpizeでこけた(泣)
dockerでPHP7.3+Laravel環境を15分で作る~2019年版

どうもautoconfが足りてないようだ。

Dockerfile
+ RUN apk add autoconf
RUN git clone https://github.com/nikic/php-ast.git \
    && cd php-ast \
    && phpize \
    && ./configure \
    && make install \
    && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \
    && cd .. && rm -rf php-ast

こうすると今度は下記のエラー。

configure: error: no acceptable C compiler found in $PATH

xdebug インストール時の error: no acceptable C compiler について

gccが足りていないということらしい。

Dockerfile
- RUN apk add autoconf
+ RUN apk add autoconf gcc
RUN git clone https://github.com/nikic/php-ast.git \
    && cd php-ast \
    && phpize \
    && ./configure \
    && make install \
    && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \
    && cd .. && rm -rf php-ast

今度は下記。

configure: error: C compiler cannot create executables

g++が足りない。

Dockerfile
- RUN apk add autoconf gcc
+ RUN apk add autoconf gcc g++
RUN git clone https://github.com/nikic/php-ast.git \
    && cd php-ast \
    && phpize \
    && ./configure \
    && make install \
    && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \
    && cd .. && rm -rf php-ast

そして下記。

make not found

makeがないということだろう。

Dockerfile
- RUN apk add autoconf gcc g++
+ RUN apk add autoconf gcc g++ make
RUN git clone https://github.com/nikic/php-ast.git \
    && cd php-ast \
    && phpize \
    && ./configure \
    && make install \
    && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \
    && cd .. && rm -rf php-ast

これは通った。

完成形

FROM node:10-alpine AS node
FROM php:7.3-fpm-alpine
MAINTAINER dyoshikawa

# install packages
RUN apk add -U --no-cache \
    bash \
    git \
    curl-dev \
    libxml2-dev \
    postgresql-dev \
    libpng-dev \
    libjpeg-turbo-dev \
    zip \
    libzip-dev \
    unzip \
    gmp-dev

# install PHP extensions
RUN docker-php-source extract
RUN cp /usr/src/php/ext/openssl/config0.m4 /usr/src/php/ext/openssl/config.m4
RUN docker-php-ext-configure gd --with-png-dir=/usr/include --with-jpeg-dir=/usr/include
RUN docker-php-ext-install pdo\
    pdo_mysql \
    mysqli \
    pdo_pgsql \
    pgsql \
    mbstring \
    curl \
    ctype \
    xml \
    json \
    tokenizer \
    openssl \
    gd \
    zip \
    gmp \
    bcmath

# install php-ast
RUN apk add --no-cache gcc g++ make autoconf
RUN git clone https://github.com/nikic/php-ast.git \
    && cd php-ast \
    && phpize \
    && ./configure \
    && make install \
    && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \
    && cd .. && rm -rf php-ast

# install composer
RUN curl -sS https://getcomposer.org/installer | php \
    && mv composer.phar /usr/local/bin/composer

# install composer plugin
RUN composer global require laravel/installer
ENV PATH=~/.composer/vendor/bin:$PATH
RUN composer global require hirak/prestissimo

# install dockerize
ENV DOCKERIZE_VERSION v0.6.1
RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
    && tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
    && rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz

# add node.js npm
COPY --from=node /usr/local /usr/local
RUN apk add --no-cache python make g++
RUN rm /usr/local/bin/yarn /usr/local/bin/yarnpkg

# add user
RUN apk add sudo shadow
RUN groupadd -g 1000 dyoshikawa
RUN useradd -u 1000 -g 1000 dyoshikawa
RUN sed -e 's/# %wheel ALL=(ALL) NOPASSWD: ALL/%wheel ALL=(ALL) NOPASSWD: ALL/g' \
    -i /etc/sudoers
RUN sed -e 's/^wheel:\(.*\)/wheel:\1,dyoshikawa/g' -i /etc/group
RUN mkdir /home/dyoshikawa && chown 1000:1000 -R /home/dyoshikawa
RUN mkdir /work && chown 1000:1000 -R /work
WORKDIR /work
USER dyoshikawa

ENTRYPOINT []
CMD php artisan serve --host 0.0.0.0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

php-alpineコンテナにxdebugをインストールする時にハマったメモ

xdebugをインストールする時に何回もコケたので、その時のエラーも含めて残します。

TL;DR

# apk add autoconf build-base
# pecl install xdebug
# docker-php-ext-enable xdebug

実際のdockerファイルはこちら https://github.com/ucan-lab/docker-laravel5/blob/master/docker/php/Dockerfile

環境

php バージョン

# php -v
PHP 7.3.4 (cli) (built: Apr 10 2019 00:12:43) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.4, Copyright (c) 1998-2018 Zend Technologies

xdebug をインストールの実行

xdebug をインストールを試みると Cannot find autoconf エラーが発生しました。

# pecl install xdebug
downloading xdebug-2.7.1.tgz ...
Starting to download xdebug-2.7.1.tgz (230,653 bytes)
.................................................done: 230,653 bytes
69 source files, building
running: phpize
Configuring for:
PHP Api Version:         20180731
Zend Module Api No:      20180731
Zend Extension Api No:   320180731
Cannot find autoconf. Please check your autoconf installation and the
$PHP_AUTOCONF environment variable. Then, rerun this script.

ERROR: `phpize' failed

autoconf パッケージが見つからないエラーです。

解決策

autoconf をインストールする。

# apk add autoconf
(1/4) Installing m4 (1.4.18-r1)
(2/4) Installing libbz2 (1.0.6-r6)
(3/4) Installing perl (5.26.3-r0)
(4/4) Installing autoconf (2.69-r2)
Executing busybox-1.29.3-r10.trigger
OK: 108 MiB in 48 packages

autoconf をインストールできたので再実行を試みます...。

xdebug インストールの再実行

xdebug をインストールを再度試みると no acceptable C compiler found エラーが発生しました。

# pecl install xdebug
downloading xdebug-2.7.1.tgz ...
Starting to download xdebug-2.7.1.tgz (230,653 bytes)
.................................................done: 230,653 bytes
69 source files, building
running: phpize
Configuring for:
PHP Api Version:         20180731
Zend Module Api No:      20180731
Zend Extension Api No:   320180731
building in /tmp/pear/temp/pear-build-defaultuserbIEBoC/xdebug-2.7.1
running: /tmp/pear/temp/xdebug/configure --with-php-config=/usr/local/bin/php-config
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for a sed that does not truncate output... /bin/sed
checking for cc... no
checking for gcc... no
configure: error: in `/tmp/pear/temp/pear-build-defaultuserbIEBoC/xdebug-2.7.1':
configure: error: no acceptable C compiler found in $PATH
See `config.log' for more details
ERROR: `/tmp/pear/temp/xdebug/configure --with-php-config=/usr/local/bin/php-config' failed

ビルドするために必要な gcc g++ make パッケージが足りないエラーです。

解決策1

build-base ビルドのためのグループパッケージが用意されているので、これをインストールします。

# apk add build-base
(1/16) Installing binutils (2.31.1-r2)
(2/16) Installing libmagic (5.35-r0)
(3/16) Installing file (5.35-r0)
(4/16) Installing gmp (6.1.2-r1)
(5/16) Installing isl (0.18-r0)
(6/16) Installing libgomp (8.3.0-r0)
(7/16) Installing libatomic (8.3.0-r0)
(8/16) Installing mpfr3 (3.1.5-r1)
(9/16) Installing mpc1 (1.0.3-r1)
(10/16) Installing gcc (8.3.0-r0)
(11/16) Installing musl-dev (1.1.20-r4)
(12/16) Installing libc-dev (0.7.1-r0)
(13/16) Installing g++ (8.3.0-r0)
(14/16) Installing make (4.2.1-r2)
(15/16) Installing fortify-headers (1.0-r0)
(16/16) Installing build-base (0.5-r1)
Executing busybox-1.29.3-r10.trigger
OK: 264 MiB in 64 packages

解決策2

個別にインストールしてもok。インストールするパッケージが少ない分、個別にした方が速い。

# apk add gcc g++ make
(1/4) Installing m4 (1.4.18-r1)
(2/4) Installing libbz2 (1.0.6-r6)
(3/4) Installing perl (5.26.3-r0)
(4/4) Installing autoconf (2.69-r2)
Executing busybox-1.29.3-r10.trigger
OK: 108 MiB in 48 packages

xdebug インストールの再々実行

# pecl install xdebug
downloading xdebug-2.7.1.tgz ...
Starting to download xdebug-2.7.1.tgz (230,653 bytes)
.................................................done: 230,653 bytes
69 source files, building
running: phpize
Configuring for:
PHP Api Version:         20180731
Zend Module Api No:      20180731
Zend Extension Api No:   320180731
building in /tmp/pear/temp/pear-build-defaultusergcLNNb/xdebug-2.7.1
running: /tmp/pear/temp/xdebug/configure --with-php-config=/usr/local/bin/php-config

... 省略 ...

Build process completed successfully
Installing '/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so'
install ok: channel://pecl.php.net/xdebug-2.7.1
configuration option "php_ini" is not set to php.ini location
You should add "zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so" to php.ini

xdebug のインストールが成功しました?

xdebug の有効化

# docker-php-ext-enable xdebug
fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/community/x86_64/APKINDEX.tar.gz
(1/1) Installing .docker-php-ext-enable-deps (0)
OK: 259 MiB in 61 packages
(1/1) Purging .docker-php-ext-enable-deps (0)
OK: 259 MiB in 60 packages

php のバージョン確認

# php -v
PHP 7.3.4 (cli) (built: Apr 10 2019 00:12:43) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.4, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.7.1, Copyright (c) 2002-2019, by Derick Rethans

with Xdebug ~ がついてるのでインストール&有効化できました!

参考

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

EC2上で大容量データを扱うElasticsearchクラスターを構築する

背景

日あたり1億レコード、2千変数を超える(セミ)スキーマレスなデータをニアリアルタイムで投入・集計したいというニーズがあったときに、EC2上でどのように構築するのがいいか?
X-Packを使いたかったのでElasticsearch Serviceが使えず、Security Groupやチューニング余地、コスト等々の都合でElastic社のマネージドサービスも選択せず、なおかつX-Packのライセンス料を最小にしたかったのでノード数も少なくしたかった。

概要

  • Elasticsearch 6.4移行を想定(5.x でもほぼ共通だがノード間通信の暗号化が必須か否か、G1GCが使えるか否か、が違う)
  • EC2インスタンスはメモリーが多いもの、256GB以上を選ぶ
  • EBSではなく、SSD(所謂エフェメラルストレージ/揮発性のNVMe)が付いてくるインスタンス、ストレージが2台以上、できれば4台くらいあるものを選択し、RAIDでストライピングする
  • ノード間の通信を暗号化するのに証明書を入れるが、手間を少なくするために一度Dockerイメージを作ってECRに入れる
  • ノードあたりのヒープサイズは128GBとか、「JVMの32GB制限」を気にせず、G1GCを有効化することで大容量メモリーと性能をバランスする
  • データノードの他に、独立したコーディネーターノードを建てる

構築手順

前提

  • インスタンスタイプはi3.8xlarge を想定
    • m5d、c5d、r5d等のNitro世代のディスク付きでも同じだが、ルートのEBSがNVMe扱いなのでデバイスの番号がずれるのでRAID構成時に注意する
  • OSは初期状態のAmazon Linux
    • ElasticsearchそのものはDocker上で動かすのであまり拘らなくて良いかもしれない

ホストマシンのチューニング

基本的な手順は公式ドキュメントと変わらないが、RAID構成をする

アップデートしてDockerをインストール

OS等の更新を適用し、Dockerをインストールしておく

yum -y update
yum -y install docker

limits.confに設定を追加

ファイルディスクリプタの上限を緩和、メモリーロックを無制限にする。
シェルで以下のように実行すれば追記される(くれぐれもlimits.confにコピペしない)

bash -c 'echo root soft nofile 1048576 >> /etc/security/limits.conf'
bash -c 'echo root hard nofile 1048576 >> /etc/security/limits.conf'
bash -c 'echo * soft nofile 1048576 >> /etc/security/limits.conf'
bash -c 'echo * hard nofile 1048576 >> /etc/security/limits.conf'
bash -c 'echo * soft memlock unlimited >> /etc/security/limits.conf'
bash -c 'echo * hard memlock unlimited >> /etc/security/limits.conf'

sysctl.confに設定を追加

ネットワークとスワップの設定をする。こちらもシェルに貼り付ければ追記できる。

bash -c 'echo net.ipv4.tcp_tw_reuse = 1 >> /etc/sysctl.conf'
bash -c 'echo net.ipv4.tcp_fin_timeout = 30 >> /etc/sysctl.conf'
bash -c 'echo net.ipv4.ip_local_port_range = 16384 65535 >> /etc/sysctl.conf'
bash -c 'echo vm.max_map_count = 262144 >> /etc/sysctl.conf'
bash -c 'echo vm.swappiness = 1 >> /etc/sysctl.conf'

/etc/rc.local に追記

/etc/rc.local を開いて以下を追記する。
ホスト名はAWSのあまり知られていない(?) 169.254.169.254 をたたいてインスタンスIDを得る。
RAIDの構成をここに書くのは、エフェメラルストレージだとシャットダウン後にデータが消えてRAIDの構成も失われるので、RAIDが構成されていなかったら構成しなおすため。
この例では i3.8xlarge を想定しているのでRAIDを組む対象デバイスが /dev/nvme0 から /dev/nvme3 の4台になっている。Nitro世代だと /dev/nvme1 から始まる。
/data をElasticsearchのデータディレクトリにするのでこうしているが、パーミッションはちゃんと考えた方がよさそう。

# Set Hostname
hostname "$(curl -s http://169.254.169.254/latest/meta-data/instance-id |sed 's/\./-/g')"

# Init RAID
if [ ! -d /data ]
then
mkdir /data  
fi

if [ ! -d /dev/md0 ]
then

# Initialize the RAID with four NVMe drives
mdadm --create --verbose --level=0 /dev/md0 --name=DATA --raid-devices=4 /dev/nvme0n1 /dev/nvme1n1 /dev/nvme2n1 /dev/nvme3n1
mkfs.ext4 /dev/md0
mdadm --detail --scan | tee -a /etc/mdadm.conf

# Just in case, Update the kernel option
dracut -H -f /boot/initramfs-$(uname -r).img $(uname -r)

# Mount the RAID
mount -a

fi

chmod 777 /data

fstabに追記

以下をシェルで実行して、構成したRAIDを起動時に /data にマウントするようにする。

bash -c 'echo /dev/md0 /data ext4 defaults,nofail,noatime,discard 0 2 >> /etc/fstab'

ホストを再起動

reboot

Elasticsearchコンテナを起動する

Dockerfileを作る

基本的にはElasticの公式イメージをベースとし、必要なプラグインを入れたりする。最近はX-Packは最初から入ってたりするので、あまり必要になるケースは多くないかもしれない。
ノード間の通信を暗号化することが必須になっているので、p12ファイルを生成してイメージに組み込んだ。(くれぐれもパブリックなリポジトリに入れないこと)

FROM docker.elastic.co/elasticsearch/elasticsearch:6.6.2

#### 形態素解析のプラグイン等インストールする場合はここに列挙する
RUN \
elasticsearch-plugin install --batch analysis-icu && \
elasticsearch-plugin install --batch analysis-kuromoji

#### ノード間の通信の暗号化に使うp12ファイルを作っておいて、よしなに入れてやる
RUN mkdir /usr/share/elasticsearch/config/certs
ADD elastic-certificates.p12 /usr/share/elasticsearch/config/certs/elastic-certificates.p12
ADD elastic-stack-ca.p12 /usr/share/elasticsearch/config/certs/elastic-stack-ca.p12
RUN chown -R elasticsearch /usr/share/elasticsearch/config/certs
RUN chgrp -R root /usr/share/elasticsearch/config/certs
RUN chmod o-rx /usr/share/elasticsearch/config/certs
RUN chmod 640 /usr/share/elasticsearch/config/certs/elastic-stack-ca.p12
RUN chmod 640 /usr/share/elasticsearch/config/certs/elastic-certificates.p12

ビルドする

ビルドする。プラグインや証明書が入ったイメージができる。
ECRに入れやすいタグを付けておく。

docker build -t 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/es/high-performance-es:6.6.2 .

ECRに入れて置く

ECRにログインして、それからプッシュ。

aws ecr get-login --no-include-email --profile hoge | sudo /bin/bash
docker push 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/es/high-performance-es:6.6.2

Elasticsearchを起動する

個々のノードで以下のようにElasticsearchコンテナを立ち上げる。
- XmsXmx はホストのメモリーの50%くらいにする。JVMの32GB(アドレス空間が32ビットか64ビットか問題)は気にしない。EC2だと31GBくらいで64ビットになった気がするけどマシンの性能が高いしG1GCを使うようにしてからなおさら気にならない。
- discovery.zen.ping.unicast.hosts にクラスターを構成するマシンのIPアドレスを列挙する
- データを格納するディレクトリは、コンテナ内で場所は変更できなかった
- ELASTIC_PASSWORD 環境変数で、デフォルトユーザーのパスワードを指定する

データノード(データを格納したり、集計処理をする)

  • データノードは node.masternode.data=truenode.ingest が全て true
docker pull 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/es/high-performance-es:6.6.2
docker run -d --net=host -v /data:/usr/share/elasticsearch/data \
-e "node.master=true" \
-e "node.data=true" \
-e "node.ingest=true" \
-e "ELASTIC_PASSWORD=P4ssW0rd" \
-e "node.name=$(curl -s http://169.254.169.254/latest/meta-data/instance-id |sed 's/\./-/g')" \
-e "ES_JAVA_OPTS=-Xms128G -Xmx128G -XX:-UseConcMarkSweepGC -XX:-UseCMSInitiatingOccupancyOnly -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=75" \
-e "network.host=0.0.0.0" \
-e "bootstrap.memory_lock=true" \
-e "discovery.zen.ping.unicast.hosts=3.0.0.1,3.0.0.2,3.0.0.3" \
-e "discovery.zen.minimum_master_nodes=1" \
-e "xpack.security.transport.ssl.enabled=true" \
-e "xpack.security.transport.ssl.verification_mode=certificate" \
-e "xpack.security.transport.ssl.keystore.path=/usr/share/elasticsearch/config/certs/elastic-stack-ca.p12" \
-e "xpack.security.transport.ssl.truststore.path=/usr/share/elasticsearch/config/certs/elastic-certificates.p12" \
-e "thread_pool.bulk.queue_size=1000" \
-e "cluster.name=high-performance-es" \
--ulimit nofile=524288:524288 --ulimit memlock=-1:-1 \
--privileged \
--name elasticsearch \
0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/es/high-performance-es:6.6.2

コーディネーターノード(入出力の窓口のみを担う)

  • コーディネーターはクラスターのエンドポイントの役割を担い、入出力をデータノードに割り振る役割
  • node.masternode.data=truenode.ingest が全て false
  • インスタンスサイズは小さくて大丈夫だが、EC2で小さいインスタンスを使う場合、ネットワーク帯域が制限されるか、クレジットの枯渇でパフォーマンスが落ちることがあるので、そこそこ大きめのインスタンスがオススメ
  • コーディネーターノードはゆとりがあるので、ここでKibanaを動かすといい
docker pull 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/es/high-performance-es:6.6.2
docker run -d --net=host -v /data:/usr/share/elasticsearch/data \
-e "node.master=false" \
-e "node.data=false" \
-e "node.ingest=false" \
-e "node.name=Coordinator" \
-e "ELASTIC_PASSWORD=P4ssW0rd" \
-e "ES_JAVA_OPTS=-Xms30G -Xmx30G -XX:-UseConcMarkSweepGC -XX:-UseCMSInitiatingOccupancyOnly -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=75" \
-e "network.host=0.0.0.0" \
-e "bootstrap.memory_lock=true" \
-e "discovery.zen.ping.unicast.hosts=3.0.0.1,3.0.0.2,3.0.0.3" \
-e "discovery.zen.minimum_master_nodes=1" \
-e "xpack.security.transport.ssl.enabled=true" \
-e "xpack.security.transport.ssl.verification_mode=certificate" \
-e "xpack.security.transport.ssl.keystore.path=/usr/share/elasticsearch/config/certs/elastic-stack-ca.p12" \
-e "xpack.security.transport.ssl.truststore.path=/usr/share/elasticsearch/config/certs/elastic-certificates.p12" \
-e "thread_pool.bulk.queue_size=1000" \
-e "cluster.name=high-performance-es" \
--ulimit nofile=524288:524288 --ulimit memlock=-1:-1 \
--privileged \
--name elasticsearch \
0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/es/high-performance-es:6.6.2

インデックス設定の調整

インデックスの設定はドキュメントのサイズ、入出力の頻度、性能要件、可用性等と相談する必要がある。特にエフェメラルストレージを使って性能を引き出している場合、ハードウェア障害が起こるとデータが失われるので、レプリカを持つのかEBSにバックアップを作るのかとか、恒久的なデータ保管は別のDBで担いElasticsearchは柔軟性と速度を重視するのかとか、選択と集中が必要。
性能に影響する設定としては以下のものが重要だと考えた。

  • refresh_interval
    • 投入したデータが反映されるまでの時間に影響する。長くすれば書き込み処理が粗くなるので軽くなるが、投入から集計までの時差=Latencyが延びる
  • number_of_shards
    • インデックスをクラスター内でいくつに分割するかの値。多すぎでも少なすぎでもよくないので難しいが、ノード数の4倍にした。インデックスあたりのドキュメント数や容量でも考える必要があるし、インデックスをどういう単位で分割するかにもよる。
  • codec
    • 圧縮設定。 best_compression でいいと思う。圧縮と伸張はCPUを使うが、ディスクIOの方が問題になるので、書き込みと読み出しの時点でのサイズを最小にする方が早い印象。
  • number_of_replicas
    • レプリカを作ればデータの保全はしやすいが、データを複製・同期するので遅くなる。最速を目指すならレプリカは作らない。
  • ドキュメントに対する制約をいじって使わないデータを扱わないようにする
    • max_docvalue_fields_search
    • total_fields
    • depth
    • nested_fields
  • analyzer
    • 変数ごとに有効・無効を切り替えられるが、形態素解析をしないような変数では基本的に無効にしておく。

終わりに

  • Dockerにしておくとアップデートの時に作業しやすい
  • Kibanaの設定は人間の工数がかかっているデータなので、S3にバックアップする方が良い。Kibanaの設定も当然クラスター内にあるので、誤ったシャットダウンや障害、作業ミスで消えると困る。
  • なにか色々はしょってる気がする
  • 誤りや更新が必要なところはコメントください
  • すでに7.0が出ている… プラグイン周りが変わったと思うけど他は使えるはず
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laradockでLaravelの環境構築をしてみる(Mac)

ローカル環境はLaradockを利用して開発します。
最終的には以下のような構成になります。

/(任意の名前)
|-- laradock
|-- laravel

1.Dockerをインストールする

Dockerのインストール

2.Laradockの入手

$ mkdir 任意のディレクトリ
$ cd 任意のディレクトリ
$ git clone https://github.com/LaraDock/laradock.git
$ cd laradock

3.laradockの設定ファイルの編集

最初にenv.exampleファイルをコピーして.envファイルを作成します。この.envファイルに環境構築時の設定情報を書き込んでいく。

$ cp env-example .env

DATAの保存する場所を変更する。標準の設定だとルートディレクトリの配下にファイルが永続化されている。
任意のディレクトリ配下のlaradockディレクトリにファイルを保存するように変更します。

# .env
# Choose storage path on your machine. For all storage systems 

- DATA_PATH_HOST=~/.laradock/data
+ DATA_PATH_HOST=.laradock/data

続いて、MYSQLの設定をしていく。

# .env
### MYSQL #################################################
MYSQL_VERSION=5.7 # versionを固定
MYSQL_DATABASE=homestead1 #データベース名を変更
MYSQL_USER=homestead1 #ユーザー名を変更
MYSQL_PASSWORD=hogehoge #パスワードを変更
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=root
MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-initdb.d

4.Dockerコンテナを起動する。

$ docker-compose up -d nginx mysql phpmyadmin

5.composerをインストールする

laradockのディレクトリ内に移動して、workspaceのbashにログインする

$ docker-compose exec --user=laradock workspace bash
$ cd training-laravel
$ composer install

6 laravelの.envの編集

laravelの.envに以下を貼り付ける

APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=homestead1
DB_USERNAME=homestead1
DB_PASSWORD=hogehoge

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

7.APP_KEYの生成と初回のマイグレーションを実行

$ docker-compose exec workspace php artisan migrate
$ docker-compose exec workspace php artisan key:generate
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerfileのARGはFROMに対しても使える

よく考えれば当たり前なのかもしれないが最近気付いたのでメモ

ARGで処理系のバージョン等を設定しておいてFROMにそれを埋め込めばmulti-stage buildを使う時にバージョンを一元管理できたりと色々便利そう

ARG RUBY_VERSION=2.6.2
ARG RAILS_ENV=production

FROM ruby:${RUBY_VERSION}-alpine AS node_modules
WORKDIR /opt/project
RUN apk add --no-cache --update nodejs yarn
ADD bin/yarn /opt/project/bin/
ADD package.json yarn.lock /opt/project/
ENV PATH=/opt/project/bin:${PATH}
RUN yarn install


FROM ruby:${RUBY_VERSION}-alpine AS bundle
WORKDIR /opt/project
RUN apk add --no-cache --update build-base mariadb-dev
ADD bin/bundle /opt/project/bin/
ADD .ruby-version .gemrc Gemfile Gemfile.lock /opt/project/
ENV PATH=/opt/project/bin:${PATH}
RUN \
if [ "${RAILS_ENV}" = "production" ]; then \
  bundle install --jobs 8 --without development test --deployment; \
else \
  bundle install --jobs 8 --without production --path vendor/bundle; \
fi


FROM ruby:${RUBY_VERSION}-alpine
WORKDIR /opt/project
RUN apk add --no-cache --update mariadb-dev tzdata nodejs yarn
COPY --from=bundle ${BUNDLE_APP_CONFIG} /opt/project/.bundle
COPY --from=bundle /opt/project/vendor/bundle /opt/project/vendor/bundle
COPY --from=node_modules /opt/project/node_modules /opt/project/node_modules
ADD . /opt/project/api
ENV RAILS_ENV=${RAILS_ENV}
ENV BUNDLE_APP_CONFIG=/opt/project/.bundle
ENV PATH=/opt/project/bin:${PATH}
ENV RAILS_SERVE_STATIC_FILES=true
RUN webpack
EXPOSE 3000
ENTRYPOINT ["rails"]
CMD ["server", "-b", "0.0.0.0"]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kind試す

いわゆる Kubernetes in Docker。(いわゆるもくそも、だから名前が "kind")

たくさんのクラスタがDockerコンテナ1つで上がる!?感じ。

Learningに使えるかという点で評価してみる。

とりあえずはセットアップと軽めのApp立ち上げ確認。

Pre Setup

  • GCPにて、約メモリ8GB積んだCentOS7 x86_64を用意
  • git
  • docker 18.09.5
  • kubectl 1.14.1

Install Golang

よしなに、

# curl -LO https://dl.google.com/go/go1.12.4.linux-amd64.tar.gz
# tar zxf go1.12.4.linux-amd64.tar.gz 
# mv go /usr/local/bin/

Install kind

# export GOPATH=/usr/local/bin/go/bin
# export PATH=$PATH:$GOPATH
# go get -u sigs.k8s.io/kind

そこそこかかる

# export KINDPATH=/usr/local/bin/go/bin/bin
# export PATH=$PATH:$KINDPATH

# kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.13.4) ?
 ✓ Preparing nodes ? 
 ✓ Creating kubeadm config ? 
 ✓ Starting control-plane ?️ 
Cluster creation complete. You can now use the cluster with:

export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
kubectl cluster-info

そこそこかかる

docker コマンドうってみると・・・・

# docker container ls
CONTAINER ID        IMAGE                  COMMAND                  CREATED              STATUS              PORTS                                  NAMES
c7f23eb8af62        kindest/node:v1.13.4   "/usr/local/bin/entr…"   About a minute ago   Up About a minute   34487/tcp, 127.0.0.1:34487->6443/tcp   kind-control-plane
# kind get kubeconfig-path
/root/.kube/kind-config-kind
# export KUBECONFIG="$(kind get kubeconfig-path)"
# kubectl cluster-info
Kubernetes master is running at https://localhost:37608
KubeDNS is running at https://localhost:37608/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

Wordpressあげてみる

https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/#add-resource-configs-for-mysql-and-wordpress

# kubectl get secrets
NAME                    TYPE                                  DATA   AGE
default-token-bkh8n     kubernetes.io/service-account-token   3      36m
mysql-pass-59cdgt95hd   Opaque                                1      14m

# kubectl get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pv-claim   Bound    pvc-a8f2baf5-5f5b-11e9-989b-0242a2b9ea4d   20Gi       RWO            standard       15m
wp-pv-claim      Bound    pvc-a8f6eb33-5f5b-11e9-989b-0242a2b9ea4d   20Gi       RWO            standard       15m

# kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
wordpress-c6b7fcdd-sfc8d         1/1     Running   0          15m
wordpress-mysql-b4447dd8-xr668   1/1     Running   0          15m

# kubectl get services wordpress
NAME        TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
wordpress   LoadBalancer   10.101.188.12   <pending>     80:32617/TCP   15m

ちゃんとあがっとるので、そとからアクセスできるようにポートフォワード

# kubectl port-forward --address 0.0.0.0 svc/wordpress 80:80

=>ブラウザで確認、ばっちりあがる!

もいっちょクラスタCreate

# kind create cluster --name tk
Creating cluster "tk" ...
 ✓ Ensuring node image (kindest/node:v1.13.4) ?
 ✓ Preparing nodes ? 
 ✓ Creating kubeadm config ? 
 ✓ Starting control-plane ?️ 
Cluster creation complete. You can now use the cluster with:

export KUBECONFIG="$(kind get kubeconfig-path --name="tk")"
kubectl cluster-info

# kind get clusters
tk
kind

追加されてる!ので宛先を変えて、再度Wordpress

# export KUBECONFIG="$(kind get kubeconfig-path --name="tk")"
# kubectl cluster-info
Kubernetes master is running at https://localhost:33629
KubeDNS is running at https://localhost:33629/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

なにがちがうって、さっきとちゃんとMasterの宛先ポートが違う。

同じYAML使ってWordpress上げて、ポートフォワーディングして、ブラウザアクセス。
ばっちりあがった。

が・・・クラスタが2つで外からのアクセスをそれぞれのクラスタのPodにアクセスするようにするのは!?

ちゃんと確認・・・これから。

クラスタ・消す

kind delete cluster --name kind

すぐ消える

Ref

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

Windows10 - Vagrant - CentOS7 - docker, docker-compose 環境構築

update 2019.04.15

Windows10 : VirtualBox , Git , Vagrant

(Git Bash : Windows)

$ git --version
git version 2.21.0.windows.1

$ vagrant --version
Vagrant 2.2.4

Vagrant : CentOS7

(Git Bash : Windows)

$ cd /c/vagrant/centos7
$ vagrant init centos/7
$ vagrant up
$ vagrant ssh
(Git Bash : Vagrant - CentOS7)

$ cat /etc/centos-release
---
CentOS Linux release 7.6.1810 (Core)
---

$ sudo yum -y update

Vagrantfile : private network (hostonly)

  • host(windows10)から、アクセス用
config.vm.network "private_network", ip: "192.168.33.10"

Vagrantfile : synced folder

  • VirtualBox Guest Additions インストール
$ vagrant plugin install vagrant-vbguest
$ vagrant vbguest
$ vagrant reload
  • host(windows10)で、ファイル編集用
config.vm.synced_folder "./docker", "/docker", owner: "vagrant", group: "vagrant", type: "virtualbox", :mount_options => ['dmode=755', 'fmode=644']

※ DNS解決できない場合...

CentOS7 : docker , docker-compose

$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ sudo yum makecache fast
$ sudo yum install -y docker-ce

$ sudo systemctl start docker
$ sudo systemctl status docker
$ sudo systemctl enable docker

$ sudo usermod -aG docker vagrant
※ 再ログイン後、反映
$ groups
---
vagrant docker
---

$ docker --version
---
Docker version 18.09.5, build e8ff056
---
  • docker hello world テスト
$ docker run hello-world
---
...
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
---

$ docker images
---
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        3 months ago        1.84kB
---

CentOS7 : docker-compose

$ sudo curl -L https://github.com/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
---
docker-compose version 1.24.0, build 0aa59064
---
  • docker-compose hello world テスト
$ mkdir -p /docker/helloworld
$ cd /docker/helloworld
$ vi docker-compose.yml
---
version: "3"
services:
  hello:
    image: hello-world
---

$ docker-compose run
---
Creating network "helloworld_default" with the default driver
Creating helloworld_hello_1 ... done
Attaching to helloworld_hello_1
hello_1  |
hello_1  | Hello from Docker!
hello_1  | This message shows that your installation appears to be working correctly.
hello_1  |
hello_1  | To generate this message, Docker took the following steps:
hello_1  |  1. The Docker client contacted the Docker daemon.
hello_1  |  2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
hello_1  |     (amd64)
hello_1  |  3. The Docker daemon created a new container from that image which runs the
hello_1  |     executable that produces the output you are currently reading.
hello_1  |  4. The Docker daemon streamed that output to the Docker client, which sent it
hello_1  |     to your terminal.
hello_1  |
hello_1  | To try something more ambitious, you can run an Ubuntu container with:
hello_1  |  $ docker run -it ubuntu bash
hello_1  |
hello_1  | Share images, automate workflows, and more with a free Docker ID:
hello_1  |  https://hub.docker.com/
hello_1  |
hello_1  | For more examples and ideas, visit:
hello_1  |  https://docs.docker.com/get-started/
hello_1  |
helloworld_hello_1 exited with code 0
---
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでGatsbyを使うときに「このページは動作していません」と出る問題について

DockerにGatsbyをインストールし、 https://www.gatsbyjs.org/tutorial/part-zero/ にある通りにHello world!を出そうとしたところ、このページは動作していませんというエラーで表示が出来ませんでした。
なにこれ困る…。

CheckPoint 1

Dockerfileの適当な場所にポートを解放する設定を書きます。

Dockerfile
# Expose port
EXPOSE 8000

CheckPoint 2

docker runコマンドにホストとコンテナのポートをつなぐオプションをつけて起動します。

docker run -p 8000:8000 -it

ホスト側のポート:コンテナ側のポートの順番です。

CheckPoint 3

https://www.gatsbyjs.org/tutorial/part-zero/#view-your-site-locally のNotesにある通り、

gatsby develop --host=0.0.0.0

としてホストオプションを指定します(上記サイトで--が一つ多いのはタイポみたいです)。

これで無事に http://localhost:8000/ にホストのブラウザからアクセスしてHello worldできました。

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

Docker環境でGLPIを9.2.1から9.3.3へアップグレード

DockerにてGLPIを利用して資産管理を行っています。
実際にGLPIで運用している日本語情報が非常に少ないです。
オフラインの機器を多数管理するような場合に非常に使いやすいと思います。

前回記事の環境からアップグレードします。
※DBのバックアップは前回から変更ありません。
※OCS Inventory NGとの連携は行っていません。

内容

  • 9.2.1から9.3.3へのアップグレード時のデータベースエラー対応
  • CASエラーについて
  • データセンターのラック管理機能を利用する

環境

Docker version 18.09.4
docker-compose version 1.24.0
hostOS:CentOS7-minimal

ベースイメージ
https://github.com/fjudith/docker-glpi
※オリジナルはmariaDBが5.5ですが10.3を使っています。

ディレクトリ構成

/glpi933
├── app
│   ├── Dockerfile
│   ├── datainjection-2.6.4.tar.gz
│   └── php.ini
├── db
│   ├── 2019mmddHHMMSS.sql
│   ├── Dockerfile
│   └── script
│     └── db_backup.sh
├── docker-compose.yml
└── glpi.env
※php.ini, db_backup.sh, glpi.envは前回と同じです。

docker-compose.yml
version: '2'
services:
  db:
    build: ./db
    env_file:
    - ./glpi.env
    environment:
    - "TZ=Japan"
    volumes:
    - glpi-db93:/var/lib/mysql
    - ./db:/docker-entrypoint-initdb.d
    - glpi-db-backup93:/backup
    ports:
    - 32806:3306/tcp
    restart: always

  app:
    build: ./app
    volumes:
    - /etc/localtime:/etc/localtime:ro
    environment:
    - "TZ=Japan"
    volumes:
    - glpi-app93:/var/www/html/
    - ./app/php.ini:/usr/local/etc/php/php.ini
    links:
    - db:mysql
    ports:
    - 8080:80/tcp
    restart: always

volumes:
  glpi-db93: {}
  glpi-db-backup93: {}
  glpi-app93: {}

Dockerfile #app ※前回から変更箇所のみ

バージョン指定

ENV GLPI_VERSION=9.3.3

nanoをvimへ変更

RUN apt-get install --no-install-recommends -yqq \
    zlib1g \
    cron \
    bzip2 \
    wget \
    vim 

プラグインのバージョンアップ

COPY datainjection-2.6.4.tar.gz /var/www/html/plugins/

WORKDIR /var/www/html
RUN tar zxvf  plugins/datainjection-2.6.4.tar.gz -C plugins/ && mv plugins/datainjection-2.6.4 plugins/datainjection
RUN rm plugins/remove.txt
EXPOSE 80
CMD apache2-foreground

Dockerfile #db

FROM mariadb:10.3
RUN apt-get update
RUN apt-get install -y  vim locales
RUN apt-get install -y language-pack-ja-base language-pack-ja
RUN locale-gen ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LC_CTYPE ja_JP.UTF-8
RUN localedef -f UTF-8 -i ja_JP ja_JP.utf8

COPY /script/db_backup.sh /opt/
RUN chmod +x /opt/db_backup.sh
RUN mkdir backup

9.2.1から9.3.3へのアップグレード時のデータベースエラー対応

参考:GLPI 9.3 convert tables to innodb
流れとしては9.2.1から9.3.3へアップグレードしデータベースのマイグレーションを実施します。
9.4系へいきなりアップグレードするとinnodb_migration.phpが存在していないためマイグレーションできません。

1.GLPI9.3.3イメージをビルド
ログイン時には以下のエラーが表示されます。
glpi-error02.jpg

2.GUIでGLPIインストール 
インストールを完了せずにマイグレーションを実行すると下記エラーが発生します。
glpi-error01.jpg

※CASエラーについて
とりあえず無視しても良いようです。
参考:GLPI フォーラム 
glpi-error-01.jpg

3.データベースをマイグレーション
appコンテナへ接続してからスクリプトを実行します。

$ docker exec -it glpi933_app_1 bash

コンテナログイン後

# php scripts/innodb_migration.php

[実行結果]
glpi-success01.jpg

4.起動確認
ブラウザで再度アクセスすると以下のようにエラーが消えています。
glpi-success02.jpg

5.install.phpを削除
ついでにinstall.phpを削除します。

$ docker exec -it glpi933_app_1 bash

コンテナログイン後

# rm /install/install.php

6.データベースをバックアップ
配置済みのスクリプトを実行

$ cd glpi933
$ docker exec glpi933_db_1 ./opt/db_backup.sh

7.バックアップの保存場所

/var/lib/docker/volumes/glpi933_glpi-db-backup/_data/

データセンターのラック管理機能

ラックイメージに情報資産で登録しているサーバを登録できます。
9.3より新たに追加された機能の一つです。

判明している課題:ポジション(ラックの何段目)の前・後・右・左が指定できるのですが登録できる機器は
1段に一つのみとなっています。1段に2つの機器を置いている場合は登録できません。
しばらく運用してみてまた感想書きたいと思います。

rack00.jpg
前・後・右・左を指定しても以下のように表示は1段を専有
rack01.jpg
登録画面では前・後・右・左を指定可能
rack02.jpg

次回試したいこと

  1. Dockerでcron登録
  2. 自動実行機能の利用
  3. GLPI 9.4へのアップグレード
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker for widnowsでdocker.errors.TLSParameterErrorが発生した場合

事象

Windows 10でDocker tool boxから、Dcoker for windowsに乗り換える際に発生

解決方法

  1. Windowsの検索機能で、キーワード環境変数を入力し、ユーザの環境変数変更画面を表示
  2. 変数名で、Docker_*となっているものを削除

参考

https://github.com/docker/for-win/issues/2706

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

最もシンプルな docker-compose.yml の hello-world

Looking for the simplest "Hello-World" docker-compose YAML file

単純な動作確認のため、docker run hello-world と同じレベルで docker-composehello world がしたい

TL;DR

docker-compose.yml
version: "3"
services:
  hello:
    image: hello-world:latest
usage
$ curl -O https://keinos.github.io/hello-docker-compose/docker-compose.yml
$ docker-compose up

TS;DR

CircleCI 実行時や Vagrantfile 内のスクリプトで Docker や Docker-Compose を自動インストールした際に、バージョン情報は返すものの、それ以外のコマンド・オプションが動かないことがありました。原因は、設定ミスで Docker デーモンの起動に失敗していたことでした。

そこで、CI を回す時や vagrant up 時にdocker run hello-world と同じくらい至極簡単な動作テストを docker-compose でしたかったのですが、docker-compose hello-world simple」とググっても Ubuntu ベースのサンプルしかありませんでした。

単純に docker-compose up で起動するかのテストであるため、そこまで大きなイメージは必要ありません。「それなら、普通に docker の hello-wolrd イメージを使えば良いじゃん」と聞こえてきたので、自分のググラビリティとして。

実行例
$ # 作業ディレクトリの作成
$ mkdir hello-world && cd $_
$ # ダウンロード(ソースをコピペして作成しても OK)
$ curl -O https://keinos.github.io/hello-docker-compose/docker-compose.yml
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    62  100    62    0     0    227      0 --:--:-- --:--:-- --:--:--   226
$ # 確認
$ ls
docker-compose.yml
$ cat docker-compose.yml
version: "3"
services:
  hello:
    image: hello-world:latest

$ # 実行
$ docker-compose up
Creating network "core_default" with the default driver
Creating core_hello_1 ... done
Attaching to core_hello_1
hello_1  | 
hello_1  | Hello from Docker!
hello_1  | This message shows that your installation appears to be working correctly.
hello_1  | 
hello_1  | To generate this message, Docker took the following steps:
hello_1  |  1. The Docker client contacted the Docker daemon.
hello_1  |  2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
hello_1  |     (amd64)
hello_1  |  3. The Docker daemon created a new container from that image which runs the
hello_1  |     executable that produces the output you are currently reading.
hello_1  |  4. The Docker daemon streamed that output to the Docker client, which sent it
hello_1  |     to your terminal.
hello_1  | 
hello_1  | To try something more ambitious, you can run an Ubuntu container with:
hello_1  |  $ docker run -it ubuntu bash
hello_1  | 
hello_1  | Share images, automate workflows, and more with a free Docker ID:
hello_1  |  https://hub.docker.com/
hello_1  | 
hello_1  | For more examples and ideas, visit:
hello_1  |  https://docs.docker.com/get-started/
hello_1  | 
core_hello_1 exited with code 0
$ # 終了結果
$ echo $?
0
動作確認済み環境
$ docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.8
 Git commit:        e68fc7a
 Built:             Tue Aug 21 17:16:31 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       e68fc7a
  Built:            Tue Aug 21 17:16:31 2018
  OS/Arch:          linux/amd64
  Experimental:     false
$ 
$ docker-compose version
docker-compose version 1.24.0, build 0aa59064
docker-py version: 3.7.2
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.1.0j  20 Nov 2018
$ 
$ cat /etc/os-release
NAME="Container Linux by CoreOS"
ID=coreos
VERSION=2023.5.0
VERSION_ID=2023.5.0
BUILD_ID=2019-03-09-0138
PRETTY_NAME="Container Linux by CoreOS 2023.5.0 (Rhyolite)"
ANSI_COLOR="38;5;75"
HOME_URL="https://coreos.com/"
BUG_REPORT_URL="https://issues.coreos.com"
COREOS_BOARD="amd64-usr"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

atom使いのためのdockerとHydrogenによるお手軽python環境構築

atomを使いたい

dockerを使うとお手軽にjupyterを使えるpython環境が手に入ります。ただjupyterをそのまま使いたくないという謎のこだわりがある。
pythonを書くときの環境はjupyter notebookが便利。最近だとjupyterLabなんかも拡張機能とかもあって楽しいらしい。(参考:https://qiita.com/canonrock16/items/d166c93087a4aafd2db4)

しかし、私はatomを使いたい。特別理由はないがatomを使いたい。

pythonに関してはatomにHydrogenというパッケージを導入すればjupyterライクに出力を得られる。ただ、SSHでリモートマシンに接続したり、dockerコンテナ上のカーネルに接続する場合多少の設定が必要になる。
今回は、いろいろあって環境がぐちゃぐちゃになったので、docker上にpython環境を用意しatom上でHydrogenを使う環境を整えたのでその流れをメモに残します。

dockerコンテナの起動

docker imageを自分で用意する時間がなかったため、jupyter環境が最初から構築してあるimageを使わせてもらった。docker hubにいろいろあるが、自分はjupyter/scipy-notebookを使わせてもらった。
詳細は省かせていただきます。
1.docker imageをpull

docker pull jupyter/scipy-notebook

2.docker imageをrun

docker run -p 8888:8888 -v ~/hoge:/home/jovyan/work jupyter-notebook start-notobook.sh —NotebookApp.token="yourpass"

オプションとして、

  • -p: コンテナのポートをホスト側に公開。
  • -v: ボリュームをマウント。フォルダの同期のため。
  • jupyter-notebook start-notobook.sh: jupyterのコマンドを使用するために必要なオプション.
  • NotebookApp.token="yourtoken": jupyter側のコマンドで、tokenを指定

tokenは指定しないと毎回変わるので指定することをオススメ。
ここで、

Executing the command: jupyter notebook --NotebookApp.token=yourtoken
[I 14:19:25.923 NotebookApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret
[I 14:19:27.362 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.7/site-packages/jupyterlab
[I 14:19:27.362 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
[I 14:19:27.365 NotebookApp] Serving notebooks from local directory: /home/jovyan
[I 14:19:27.366 NotebookApp] The Jupyter Notebook is running at:
[I 14:19:27.367 NotebookApp] http://(***):8888/?token=…
[I 14:19:27.367 NotebookApp]
Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).

とでてきてdockerコンテナ上にjupyter kernelが起動できた。

ここまでできたら、Hydrogenへの設定へ。

Hydrogenの準備

調べればたくさん丁寧に説明してくれてる記事があるので、Hydrogenのインストール等は省略する。(こことか)

atomのpacageからHydrogenの設定画面へ行き、Kernel Gatewayというところに、こんな感じで記入。

スクリーンショット 2019-04-14 23.50.01.png
nameは自分の好きなものを、baseUrlはdockerを起動したときにでてきたurlをコピペ、tokenは自分で設定したtokenを記入。
詳細はここ参照。

Hydrogenからリモートカーネルへ接続

  1. atomの画面からコマンドパレットを開き,Hydrogen:Connect To Remote Kernelを選択。 スクリーンショット 2019-04-14 23.57.05.png 2.remote kernelが見つかれば次のように出てくるので、使いたいカーネルを選択。

スクリーンショット 2019-04-14 23.59.22.png
3.セッションを選択。
スクリーンショット 2019-04-14 23.59.43.png

ここまできたら、あとは通常のHydrogenと同じように使えるはず。

まとめ

Hydrogenを使えば、atomのエディタ機能を使いながらjupyterのインタラクティブな機能をふんだんに使える。jupyter用のショートカットを覚える必要もない。docker使えば環境設定の必要もほぼいらない。python使う人はatomとHydrogen使いましょ。
(jupyter labとかは進化が目まぐるしいので、ちょっとさわってもいいかな・・・)

ssh接続でリモートマシン上のカーネルを使いたいときも同じようにできると思います。

参考

Jupyterをブラウザで使うのをやめてAtomのHydrogenに移行した話
JupyterのDockerイメージまとめ
Hydrogen
jupyter docker stacks

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

[mastodon]v2.4.0→v2.4.1にアップデートした際のエラー

※とりま備忘録的に書いてます+ markdown文法 模索中です

環境

うちのmastdon
vps
docker
mastodon v2.4.0→v2.4.1

v2.4.0→v2.4.1にアップデートした際に出たエラー

いつも通りに「docker-compose run --rm web rails db:migrate」とやっていたら、エラー吐いたので、対応模索する。

~/mstdntest$ docker-compose run --rm web rails db:migrate
Starting mstdntest_db_1    ... done
Starting mstdntest_redis_1 ... done
[FATAL tini (11)] exec rails failed: No such file or directory
~$ cd mstdntest/
~/mstdntest$ docker-compose run --rm web rails assets:precompile
Starting mstdntest_db_1    ... done
Starting mstdntest_redis_1 ... done
[FATAL tini (8)] exec rails failed: No such file or directory

「rails」が見つからん
と仰っているのでパスを付与する

~$ cd mstdntest/
~/mstdntest$ docker-compose run --rm web ./bin/rails db:migrate
Starting mstdntest_db_1    ... done
Starting mstdntest_redis_1 ... done
~/mstdntest$ docker-compose run --rm web ./bin/rails assets:precompile
Starting mstdntest_db_1 ... done
Starting mstdntest_redis_1 ... done
Webpacker is installed ? ?
Using /mastodon/config/webpacker.yml file for setting up webpack paths
Compiling…
Compiled all packs in /mastodon/public/packs
~/mstdntest$

※assets:precompileは、5分ぐらいかかった

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

mastodon v2.4.0→v2.4.1にアップデートした際のエラー

※とりま備忘録的に書いてます+ markdown文法 模索中です

うちのmastdon
vps
docker
mastodon v2.4.0→v2.4.1

v2.4.0→v2.4.1にアップデートした際に出たエラー

いつも通りに「docker-compose run --rm web rails db:migrate」とやっていたら、エラー吐いたので、対応模索する。

Console
docker@altair:~/mstdntest$ docker-compose run --rm web rails db:migrate
Starting mstdntest_db_1    ... done
Starting mstdntest_redis_1 ... done
[FATAL tini (11)] exec rails failed: No such file or directory
Console
docker@altair:~$ cd mstdntest/
docker@altair:~/mstdntest$ docker-compose run --rm web rails assets:precompile
Starting mstdntest_db_1    ... done
Starting mstdntest_redis_1 ... done
[FATAL tini (8)] exec rails failed: No such file or directory

「rails」が見つからないよー
と仰っているのでパスを付与する

Console
docker@altair:~$ cd mstdntest/
docker@altair:~/mstdntest$ docker-compose run --rm web ./bin/rails db:migrate
Starting mstdntest_db_1    ... done
Starting mstdntest_redis_1 ... done
Console
docker@altair:~/mstdntest$ docker-compose run --rm web ./bin/rails assets:precompile
Starting mstdntest_db_1 ... done
Starting mstdntest_redis_1 ... done
Webpacker is installed ? ?
Using /mastodon/config/webpacker.yml file for setting up webpack paths
Compiling…
Compiled all packs in /mastodon/public/packs
docker@altair:~/mstdntest$

※assets:precompileは、5分ぐらいかかった

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

素の alpine でのコネクション確認

最近 ECS を使おうと docker を色々と触っているので、その知見を溜めておく。

今回は alpine で一切ツールを導入(apk add)せずにコネクション確認をするかというお話。「ヘルスチェック」ではなく「コネクション確認」という言葉を使っているのは、docker が持っているヘルスチェック機能とは違う話をするため。
応用はできるけど、もともとの動機は「アプリサーバーがDBマイグレーションを行う際に通信できる常態か知りたい」だった。

tl;dr

nc コマンドを使おう。
デフォルトでインストールされていて、なんなら UDP での接続チェックなんてのもできる。

一定の時間、コネクション確認するスクリプトは次の通り。

host=${1:-"127.0.0.1"}
port=${2:-80}

retry=0
while [ $retry -lt 10 ];
do
    sleep $retry
    echo "connection check to $host:$port"
    nc -zn $host $port
    [ $? -eq 0 ] && exit 0

    retry=`expr $retry + 1`
    echo "failed; sleep for ${retry}s"
done && exit 1

というわけで、以下は道のり
を書こうと思ったけど、まぁまた今度

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

Kubernetes上でアプリケーションデプロイをサクッと試してみる(コマンド例あり)

背景

最近アプリケーション実行環境としてコンテナ仮想環境は当たり前になりつつあると感じています。個人的にもサクッと新しい技術を(OSSなりツールなり)試したりするのにもローカルを汚さず素早く環境構築を行えるので、これがないと逆に効率が悪くなるなと思います。

そんな風潮の中で社内でもKubernetesによるアプリケーション環境構築や運用保守がなされており、(コンテナ仮想化ソフトはもう当たり前として)社内外でもk8sの存在感が絶大です。

僕自身はアプリケーションエンジニア(フロントエンド/バックエンドどちらも見る)ではありますが、k8sの知見を増やしたいと思い「Kubernetes実践入門」という書籍を参考にローカルにk8sでアプリケーションデプロイまで構築してみました。目次は書籍の章立てとはあまり関係なく試したことの備忘的な面が大きいですが、順序だてていますので試しに触って動かしてみたい方には参考になるかなと思います。

目次

前提

  • MacbookPro, MacOS Mojave(version=10.14.3)
  • VirtualBox(version=5.2.20 r125813)
  • Homebrew(version=2.1.0)
  • k8sのオブジェクトについて概ね理解している。

k8sには内部構造を抽象化しk8s内で利用しやすくするために独自のオブジェクトの概念があります。僕自身は以前k8sについて調べたことがあったので(知見として頭に入れただけで使えるようにはなってませんでした)あえてそこには触れませんが、記事内では固有名詞で頻出しますのでわからない方は以下の記事などで先に理解しておくことをお勧めします。(まぁそれを理解するのがもっとも難しいのですが。。。)

【参考記事】

minikubeでクラスタを構築してみる

ローカル環境でk8sを動かすためにminikubeを利用します。k8sの公式で提供しているので操作についてほとんど差異はないはずです。

インストール方法

# minikubeをインストール
$ brew cask install minikube

# kubernetes-cliをインストール
$ brew install kubernetes-cli

クラスタ構築

初回実行時はVMイメージのダウンロードから始まるので時間がかかるようです。
(実は、一度失敗してしまったのでこちらの記事を参考に再実行しました。)

$ minikube start
?  minikube v1.0.0 on darwin (amd64)
?  Downloading Kubernetes v1.14.0 images in the background ...
?  Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...
?  Downloading Minikube ISO ...
 142.88 MB / 142.88 MB [============================================] 100.00% 0s
?  "minikube" IP address is 192.168.99.100
?  Configuring Docker as the container runtime ...
?  Version of container runtime is 18.06.2-ce
⌛  Waiting for image downloads to complete ...
✨  Preparing Kubernetes environment ...
?  Downloading kubeadm v1.14.0
?  Downloading kubelet v1.14.0
?  Pulling images required by Kubernetes v1.14.0 ...
?  Launching Kubernetes v1.14.0 using kubeadm ... 
⌛  Waiting for pods: apiserver proxy etcd scheduler controller dns
?  Configuring cluster permissions ...
?  Verifying component health .....
?  kubectl is now configured to use "minikube"
?  Done! Thank you for using minikube!

クラスタの確認をしてみる

$ kubectl get nodes
NAME       STATUS   ROLES    AGE     VERSION
minikube   Ready    master   2m23s   v1.14.0

minikubeという1台のNodeが稼働しています。

クラスタの停止、削除する

minikubeはローカルでクラスタを実行しているため実行中ノードのリソースを占有するようです。よって利用しない場合はクラスを終了しておいた方がいいでしょう。
クラスタを停止して再度minikube startした際は、停止前の状態のクラスタ起動します。削除した場合は初期状態のクラスタが構築されますのでリセットしたい場合に利用できると思います。

# クラスタを停止する
$ minikube stop

# クラスタを削除する
$ minikube delete

アドオンを管理する

minikubeにはよく使われる機能を拡張機能として利用できるアドオンがあります。

# アドオンの一覧を列挙する
$ minikube addons list
- addon-manager: enabled
- dashboard: disabled
- default-storageclass: enabled
- efk: disabled
- freshpod: disabled
- gvisor: disabled
- heapster: disabled
- ingress: disabled
- logviewer: disabled
- metrics-server: disabled
- nvidia-driver-installer: disabled
- nvidia-gpu-device-plugin: disabled
- registry: disabled
- registry-creds: disabled
- storage-provisioner: enabled
- storage-provisioner-gluster: disabled

デフォルトでいくつかのアドオンが有効になっています。アドオンを有効/無効にする場合は以下を実行します。

# アドオンを有効にする
$ minikube addons enable {addon-name}

# アドオンを無効にする
$ minikube addons disable {addon-name}

たとえば、クラスタのWEB管理画面であるdashboardminikube dashboardを実行することでブラウザで表示されます。

k8s dashboardの画面
k8s dashboardの画面.png

k8s上にアプリケーションをデプロイしてみる

サンプルアプリにはMattermostというSlackライクなチャットアプリケーションを利用します。

簡易的にデプロイする

ここからは、k8s上へのアプリデプロイを素早くやってみたい、デプロイされた後の動きをdashboardで確認してみたいと思い、プロセスや本番利用をすっ飛ばした簡易的なデプロイ手順を記載しています。本番環境では利用をおすすめしませんのでより本番に近い方法は こちら に進んでください。

アプリケーションをデプロイする - kubectl create deployment

k8上にアプリケーションをデプロイする簡単な方法はkubectl create deploymentを実行することです。アプリケーションの識別名とコンテナイメージの指定は必須です。
createdが返ればDeploymentオブジェクトが作成され、デプロイが開始したことを意味します。

$ kubectl create deployment mattermost-preview --image k8spracticalguide/mattermost-preview:4.10.2
deployment.apps/mattermost-preview created

デプロイが開始されれば、kubectl get deploymentを実行してDeploymentの状態を確認しましょう。何度か実行しているうちにAVAILABLEが1に変わると思います。

$ kubectl get deployment mattermost-preview
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
mattermost-preview   1/1     1            1           69s

アプリケーションを公開する - kubectl expose

デプロイが完了しても、クラスタ外からはアクセスできません。クラスタ外からアクセスできるようにするにはkubectl exposeコマンドを--typeオプションにNodePortを指定して実行する必要があります。
ただ、僕自身現段階では「Nodeportはクラスタ外からアクセスするためのもの」という理解しかしていませんでした。。。

$ kubectl expose --type NodePort --port 8065 deployment mattermost-preview
service/mattermost-preview exposed

以上でクラスタ外からアクセスできる状態になったので、ブラウザから確認してみます。ブラウザからアクセスするには、アプリケーションのアドレスとポート番号を調べ、ブラウザを開き・・という少々面倒ですので、それらを一括で実行してくれるminikube serviceコマンドを使います。

$ minikube service mattermost-preview
?  Opening kubernetes service default/mattermost-preview in default browser...

mattermostの画面
mattermostの画面.png

アプリケーションのマニフェストを作成してデプロイする

上記ではkubectl create deploymentを利用して簡易的にDeploymentを作成しましたが、これではファイルとして履歴が残らないため、レビューしにくく、再利用ができず、問題発生時に原因究明しにくいなど本番環境で利用するには問題が起きそうです。
そのため本番利用を見据えては、Deploymentなどの宣言的設定をyamlやjsonなどで記述しバージョン管理を行うのが一般的かと思います。それらの設定ファイルをマニフェストと呼びます。

ここからアプリコンテナは、mattermostのお試し用(mattermost-preview)ではなく、実利用版(mattermost)を利用していきます。

Deploymentマニフェストを作成する

いきなり0から作るのは難しいため、--dry-runオプションで雛形を作成し、修正しながら作成していくこととします。

--dry-runオプションは雛形作成のためのオプションではなく、実際にkubectrlがAPIを叩く前のリクエスト内容を取得するためのコマンドです。外部出力の--outputオプションと併用して雛形作成を行います。

# mattermost(アプリ)の雛形を作成
$ kubectl create deployment mattermost --image k8spracticalguide/mattermost:4.10.2 -o yaml --dry-run > mattermost-deploy.yaml

# mattermost-db(db)の雛形を作成
$ kubectl create deployment mattermost-db --image k8spracticalguide/mysql:5.7.22 -o yaml --dry-run > mattermost-db-deploy.yaml

DeploymetnマニュフェストのPodテンプレートに環境変数を追加する

mattermostのイメージはDB用の設定値を環境変数で定義できるようになっています。

これらはデプロイする環境や構成によって変更する可能性があるため、コンテナイメージに直接持つのではなく、Deploymentオブジェクト作成時に設定するようにしたいと思います。

ConfigMapを使って設定値を管理、読み込みする

複数のPodテンプレート内に共通の設定値を与える場合、ConfigMapというオブジェクトに設定値を集約して設定値のばらつきによる不具合を抑えることができます。

# ConfigMapのマニフェストを作成する
$ kubectl create cm common-env -o yaml --dry-run \
 --from-literal MYSQL_USER=mm_user \
 --from-literal MYSQL_PASSWORD=P@ssw0rd \
 --from-literal MYSQL_DATABASE=mattermost > cm.yaml

Deploymentの方は以下のように修正する。

mattermost-deploy.yaml
(1~18行目は略)
    spec:
      containers:
      - image: k8spracticalguide/mattermost:4.10.2
        name: mattermost
+       env:
+       - name: MM_USERNAME
+         valueFrom:            # <- valueではなくvalueFromを使う
+           configMapKeyRef:
+             name: common-env  # <- ConfigMap名を指定する
+             key: MYSQL_USER   # <- dataマップのキーを指定する
+       - name: MM_PASSWORD
+         valueFrom:
+           configMapKeyRef:
+             name: common-env
+             key: MYSQL_PASSWORD
+       - name: DB_NAME
+         valueFrom:
+           configMapKeyRef:
+             name: common-env
+             key: MYSQL_DATABASE
+       - name: DB_HOST
+         value: mattermost-db
        resources: {}
(略)
mattermost-db-deploy.yaml
(1~18行目は略)
    spec:
      containers:
      - image: k8spracticalguide/mysql:5.7.22
        name: mysql
+       env:
+       - name: MYSQL_ROOT_PASSWORD
+         value: rootpassword
+       envFrom:                # <- envではなくenvFromに置き換える
+       - configMapRef:
+           name: common-env    # <- ConfigMap名を指定する
        resources: {}
(略)

別ファイルで設定値を管理、読み込みする

さらに、設定が膨大に増えると環境変数として渡すのではなく設定ファイルとしてまとめて設定値を渡す方が管理しやすくなることもあります。

# mattermostの設定ファイルをダウンロードしておく
$ curl -L -O https://raw.githubusercontent.com/kubernetes-practical-guide/examples/master/ch3.4.2.2/config.json

# ファイルからConfigMapのマニフェストを作成する
$ kubectl create cm mm-config-file -o yaml --dry-run \
 --from-file ./config.json > cm-file.yaml

# ダウンロードした設定ファイルは不要なので削除する
$ rm ./config.json

Deploymentの方は以下のように修正する。

mattermost-deploy.yaml
(1~38行目は略)
        - name: DB_HOST
          value: mattermost-db
        resources: {}
+       volumeMounts:
+       - name: cm-volume       # <- マウントするVolume名を指定(a)
+         mountPath: /mm/config # <- コンテナ内のマウントポイント
+     volumes:
+     - name: cm-volume         # <- (a)で指定するVolume名を定義
+       configMap:
+         name: mm-config-file
+         items:                # <- itemsを省略するとConfigMap内の全データがマウントされる
+         - key: config.json    # <- ファイルとしてマウントするデータのキーを指定
+           path: config.json   # <- コンテナ内でのファイル名を指定
(略)

Serviceマニフェストを作成する

各PodはデプロイされるとIPアドレスが一時的に付与されますが、Podを上げ下げするたびにIPアドレスが変更され書き換えが必要になります。
その無駄を回避するため、PodのIPアドレスを仮想IPに束ね内部DNSで名前解決するServieオブジェクトが存在しています。

クラスタ内部のためのServiceを作成する

$ kubectl create service clusterip mattermost-db --tcp 3306 -o yaml --dry-run > mattermost-db-service.yaml

仮想IPに来たアクセスをどのPodへ振り分けするかはservie.yamlのspec.selectorで指定します。

mattermost-db-service.yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: mattermost-db
  name: mattermost-db
spec:
  ports:
  - name: "3306"
    port: 3306
    protocol: TCP
    targetPort: 3306
  selector:                 # <- リクエストの振り分け先を指定するlabelセレクタ
    app: mattermost-db      # <- DeploymentのPodテンプレートのlabelと合わせる必要がある
  type: ClusterIP
status:
  loadBalancer: {}

クラスタ外のための(公開用)Serviceを作成する

# mattermostのDeploymentにServiceを付与するので事前に立ち上げておく
$ kubectl apply -f .

# クラスタ外のための(公開用)Serviceを作成する
$ kubectl expose --type NodePort --port 8065 deploy mattermost -o yaml --dry-run > mattermost-service.yaml

※ NodePortを使えば手軽に外部公開できるようになりますが、直接Serviceを晒す事になったり、アクセスするNodeをどう選択するか問題になりがちです。いくらマニフェスト化して管理しやすくしてもまだ本番利用には不向きだと思いました。開発環境をサクッと構築したい時には便利です。
よって本番では、外部のロードバランサを使って公開するか、Ingressというクラスタ内部のロードバランサを使って公開する方法が有用ですが、今回は構築は実施しません。
(両者の違いについてはこちらが参考になりました。)

マニフェストを適用する

上記の通り操作してくるとマニフェストファイル構成は以下のようになっているはず。

┌ cm-file.yaml  
├ cm.yaml  
├ mattermost-db-deploy.yaml  
├ mattermost-db-service.yaml  
├ mattermost-deploy.yaml  
└ mattermost-service.yaml  

マニフェストファイルを適用して各種k8sオブジェクトを作成する

$ kubectl apply -f .

ブラウザからアクセスできることを確認するためにNodeのIP、Nodeに割り当てられたポート番号を調べます。

# NodeのIPアドレスを調べる
$ minikube ip
192.168.99.100

# NodePortに割り当てられたのポート番号を調べる
$ kubectl get svc mattermost
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
mattermost   NodePort   10.102.242.69   <none>        8065:31837/TCP   3m50s

PORT(s)のカラムをみると、2つのポート番号が表示されていますが、{アプリが待ち受けしているポート}:{Nodeに割り当てられたポート}を表しています。

よってhttp://192.168.99.100:31837でブラウザからアクセスできるはずです。

今回は以上です。

サクッと利用してみたいのであればk8sのマネージドサービスも一般的かもしれませんが、利便性の反面、内部の仕組みが隠蔽されて仕組みを理解する題材には向いていないかなと思いましてローカルにminikubeでk8s環境を立ててみました。今回の内容はまだまだ入り口かとは思いますが、実際にアプリケーションをデプロイすることを実践してみてk8sの足がかりになったかなと思います。

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

Kubernetes上でアプリケーションデプロイをサクッと試してみる(コマンドあり)

背景

最近アプリケーション実行環境としてコンテナ仮想環境は当たり前になりつつあると感じています。個人的にもサクッと新しい技術を(OSSなりツールなり)試したりするのにもローカルを汚さず素早く環境構築を行えるので、これがないと逆に効率が悪くなるなと思います。

そんな風潮の中で社内でもKubernetesによるアプリケーション環境構築や運用保守がなされており、(コンテナ仮想化ソフトはもう当たり前として)社内外でk8sの存在感が絶大です。

僕自身はアプリケーションエンジニア(フロントエンド/バックエンドどちらも見る)ではありますが、k8sの知見を増やしたいと思い「Kubernetes実践入門」という書籍を参考にローカルにk8sでアプリケーションデプロイまで構築してみました。目次は書籍の章立てとはあまり関係ないですが特に重要と思われる部分だけピックアップし順序だてていますので試しに触って動かしてみたい方には参考になるかなと思います。

目次

前提

  • MacbookPro, MacOS Mojave(version=10.14.3)
  • VirtualBox(version=5.2.20 r125813)
  • Homebrew(version=2.1.0)
  • k8sのオブジェクトについて概ね理解している。

k8sには内部構造を抽象化しk8s内で利用しやすくするために独自のオブジェクトの概念があります。僕自身は以前k8sについて調べたことがあったので(知見として頭に入れただけで使えるようにはなってませんでした)あえてそこには触れませんが、記事内では固有名詞で頻出しますのでわからない方は以下の記事などで先に理解しておくことをお勧めします。(まぁそれを理解するのがもっとも難しいのですが。。。)

【参考記事】

minikubeでクラスタを構築してみる

ローカル環境でk8sを動かすためにminikubeを利用します。k8sの公式で提供しているので操作についてほとんど差異はないはずです。

インストール方法

# minikubeをインストール
$ brew cask install minikube

# kubernetes-cliをインストール
$ brew install kubernetes-cli

クラスタ構築

初回実行時はVMイメージのダウンロードから始まるので時間がかかるようです。
(実は、一度失敗してしまったのでこちらの記事を参考に再実行しました。)

$ minikube start
?  minikube v1.0.0 on darwin (amd64)
?  Downloading Kubernetes v1.14.0 images in the background ...
?  Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...
?  Downloading Minikube ISO ...
 142.88 MB / 142.88 MB [============================================] 100.00% 0s
?  "minikube" IP address is 192.168.99.100
?  Configuring Docker as the container runtime ...
?  Version of container runtime is 18.06.2-ce
⌛  Waiting for image downloads to complete ...
✨  Preparing Kubernetes environment ...
?  Downloading kubeadm v1.14.0
?  Downloading kubelet v1.14.0
?  Pulling images required by Kubernetes v1.14.0 ...
?  Launching Kubernetes v1.14.0 using kubeadm ... 
⌛  Waiting for pods: apiserver proxy etcd scheduler controller dns
?  Configuring cluster permissions ...
?  Verifying component health .....
?  kubectl is now configured to use "minikube"
?  Done! Thank you for using minikube!

クラスタの確認をしてみる

$ kubectl get nodes
NAME       STATUS   ROLES    AGE     VERSION
minikube   Ready    master   2m23s   v1.14.0

minikubeという1台のNodeが稼働しています。

クラスタの停止、削除する

minikubeはローカルでクラスタを実行しているため実行中ノードのリソースを占有するようです。よって利用しない場合はクラスを終了しておいた方がいいでしょう。
クラスタを停止して再度minikube startした際は、停止前の状態のクラスタが起動します。削除した場合は初期状態のクラスタが起動されますのでリセットしたい場合に利用できます。

# クラスタを停止する
$ minikube stop

# クラスタを削除する
$ minikube delete

アドオンを管理する

minikubeにはよく使われる機能を拡張機能として利用できるアドオンがあります。

# アドオンの一覧を列挙する
$ minikube addons list
- addon-manager: enabled
- dashboard: disabled
- default-storageclass: enabled
- efk: disabled
- freshpod: disabled
- gvisor: disabled
- heapster: disabled
- ingress: disabled
- logviewer: disabled
- metrics-server: disabled
- nvidia-driver-installer: disabled
- nvidia-gpu-device-plugin: disabled
- registry: disabled
- registry-creds: disabled
- storage-provisioner: enabled
- storage-provisioner-gluster: disabled

デフォルトでいくつかのアドオンが有効になっています。アドオンを有効/無効にする場合は以下を実行します。

# アドオンを有効にする
$ minikube addons enable {addon-name}

# アドオンを無効にする
$ minikube addons disable {addon-name}

たとえば、クラスタのWEB管理画面であるdashboardminikube dashboardを実行することでブラウザで表示されます。

k8s dashboardの画面
k8s dashboardの画面.png

k8s上にアプリケーションをデプロイしてみる

サンプルアプリにはMattermostというSlackライクなチャットアプリケーションを利用します。

簡易的にデプロイする

ここからは、k8s上へのアプリデプロイを素早くやってみたい、デプロイされた後の動きをdashboardで確認してみたいと思い、簡易的なデプロイ手順を記載しています。本番環境では利用をおすすめしませんのでより本番に近い方法は こちら に進んでください。

アプリケーションをデプロイする - kubectl create deployment

k8上にアプリケーションをデプロイする簡単な方法はkubectl create deploymentを実行することです。アプリケーションの識別名とコンテナイメージの指定は必須です。
createdが返ればDeploymentオブジェクトが作成され、デプロイが開始したことを意味します。

$ kubectl create deployment mattermost-preview --image k8spracticalguide/mattermost-preview:4.10.2
deployment.apps/mattermost-preview created

デプロイが開始されれば、kubectl get deploymentを実行してDeploymentの状態を確認しましょう。何度か実行しているうちにAVAILABLEが1に変わると思います。

$ kubectl get deployment mattermost-preview
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
mattermost-preview   1/1     1            1           69s

アプリケーションを公開する - kubectl expose

デプロイが完了しても、クラスタ外からはアクセスできません。クラスタ外からアクセスできるようにするにはkubectl exposeコマンドを--typeオプションにNodePortを指定して実行する必要があります。
現段階では「Nodeportはクラスタ外からNodeへアクセスするためのポート」という理解で良いと思います。。。

$ kubectl expose --type NodePort --port 8065 deployment mattermost-preview
service/mattermost-preview exposed

以上でクラスタ外からアクセスできる状態になったので、ブラウザから確認してみます。ブラウザからアクセスするには、アプリケーションのアドレスとポート番号を調べ、ブラウザを開き・・という少々面倒ですので、それらを一括で実行してくれるminikube serviceコマンドを使います。

$ minikube service mattermost-preview
?  Opening kubernetes service default/mattermost-preview in default browser...

mattermostの画面
mattermostの画面.png

アプリケーションのマニフェストを作成してデプロイする

上記ではkubectl create deploymentを利用して簡易的にDeploymentを作成しましたが、これではファイルとして履歴が残らないため、レビューしにくく、再利用ができず、問題発生時に原因究明しにくいなど本番環境で利用するには問題が起きそうです。
そのため本番利用を見据えては、Deploymentなどの宣言的設定をyamlやjsonなどで記述しバージョン管理を行うのが一般的かと思います。それらの設定ファイルをマニフェストと呼びます。

ここからアプリコンテナは、mattermostのお試し用(mattermost-preview)ではなく、実利用版(mattermost)を利用していきます。

Deploymentマニフェストを作成する

いきなり0から作るのは難しいため、--dry-runオプションで雛形を作成し、修正しながら作成していくこととします。

--dry-runオプションは雛形作成のためのオプションではなく、実際にkubectrlがAPIを叩く前のリクエスト内容を取得するためのコマンドです。外部出力の--outputオプションと併用して雛形作成を行います。

# mattermost(アプリ)の雛形を作成
$ kubectl create deployment mattermost --image k8spracticalguide/mattermost:4.10.2 -o yaml --dry-run > mattermost-deploy.yaml

# mattermost-db(db)の雛形を作成
$ kubectl create deployment mattermost-db --image k8spracticalguide/mysql:5.7.22 -o yaml --dry-run > mattermost-db-deploy.yaml

DeploymetnマニュフェストのPodテンプレートに環境変数を追加する

mattermostのイメージはDB用の設定値を環境変数で定義できるようになっています。

これらはデプロイする環境や構成によって変更する可能性があるため、コンテナイメージに直接持つのではなく、Deploymentオブジェクト作成時に設定するようにしたいと思います。

ConfigMapを使って設定値を管理、読み込みする

複数のPodテンプレート内に共通の設定値を与える場合、ConfigMapというオブジェクトに設定値を集約して設定値のばらつきによる不具合を抑えることができます。

# ConfigMapのマニフェストを作成する
$ kubectl create cm common-env -o yaml --dry-run \
 --from-literal MYSQL_USER=mm_user \
 --from-literal MYSQL_PASSWORD=P@ssw0rd \
 --from-literal MYSQL_DATABASE=mattermost > cm.yaml

Deploymentの方は以下のように修正する。

mattermost-deploy.yaml
(1~18行目は略)
    spec:
      containers:
      - image: k8spracticalguide/mattermost:4.10.2
        name: mattermost
+       env:
+       - name: MM_USERNAME
+         valueFrom:            # <- valueではなくvalueFromを使う
+           configMapKeyRef:
+             name: common-env  # <- ConfigMap名を指定する
+             key: MYSQL_USER   # <- dataマップのキーを指定する
+       - name: MM_PASSWORD
+         valueFrom:
+           configMapKeyRef:
+             name: common-env
+             key: MYSQL_PASSWORD
+       - name: DB_NAME
+         valueFrom:
+           configMapKeyRef:
+             name: common-env
+             key: MYSQL_DATABASE
+       - name: DB_HOST
+         value: mattermost-db
        resources: {}
(略)
mattermost-db-deploy.yaml
(1~18行目は略)
    spec:
      containers:
      - image: k8spracticalguide/mysql:5.7.22
        name: mysql
+       env:
+       - name: MYSQL_ROOT_PASSWORD
+         value: rootpassword
+       envFrom:                # <- envではなくenvFromに置き換える
+       - configMapRef:
+           name: common-env    # <- ConfigMap名を指定する
        resources: {}
(略)

別ファイルで設定値を管理、読み込みする

さらに、設定が膨大に増えると環境変数として渡すのではなく設定ファイルとしてまとめて設定値を渡す方が管理しやすくなることもあります。

# mattermostの設定ファイルをダウンロードしておく
$ curl -L -O https://raw.githubusercontent.com/kubernetes-practical-guide/examples/master/ch3.4.2.2/config.json

# ファイルからConfigMapのマニフェストを作成する
$ kubectl create cm mm-config-file -o yaml --dry-run \
 --from-file ./config.json > cm-file.yaml

# ダウンロードした設定ファイルは不要なので削除する
$ rm ./config.json

Deploymentの方は以下のように修正する。

mattermost-deploy.yaml
(1~38行目は略)
        - name: DB_HOST
          value: mattermost-db
        resources: {}
+       volumeMounts:
+       - name: cm-volume       # <- マウントするVolume名を指定(a)
+         mountPath: /mm/config # <- コンテナ内のマウントポイント
+     volumes:
+     - name: cm-volume         # <- (a)で指定するVolume名を定義
+       configMap:
+         name: mm-config-file
+         items:                # <- itemsを省略するとConfigMap内の全データがマウントされる
+         - key: config.json    # <- ファイルとしてマウントするデータのキーを指定
+           path: config.json   # <- コンテナ内でのファイル名を指定
(略)

Serviceマニフェストを作成する

各PodはデプロイされるとIPアドレスが一時的に付与されますが、Podを上げ下げするたびにIPアドレスが変更され書き換えが必要になります。
その無駄を回避するため、PodのIPアドレスを仮想IPに束ね内部DNSで名前解決するServieオブジェクトが存在しています。

クラスタ内部のためのServiceを作成する

$ kubectl create service clusterip mattermost-db --tcp 3306 -o yaml --dry-run > mattermost-db-service.yaml

仮想IPに来たアクセスをどのPodへ振り分けするかはservie.yamlのspec.selectorで指定します。

mattermost-db-service.yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: mattermost-db
  name: mattermost-db
spec:
  ports:
  - name: "3306"
    port: 3306
    protocol: TCP
    targetPort: 3306
  selector:                 # <- リクエストの振り分け先を指定するlabelセレクタ
    app: mattermost-db      # <- DeploymentのPodテンプレートのlabelと合わせる必要がある
  type: ClusterIP
status:
  loadBalancer: {}

クラスタ外のための(公開用)Serviceを作成する

# mattermostのDeploymentにServiceを付与するので事前に立ち上げておく
$ kubectl apply -f .

# クラスタ外のための(公開用)Serviceを作成する
$ kubectl expose --type NodePort --port 8065 deploy mattermost -o yaml --dry-run > mattermost-service.yaml

※ NodePortを使えば手軽に外部公開できるようになりますが、直接Serviceを晒す事になったり、アクセスするNodeをどう選択するか問題になりがちです。いくらマニフェスト化して管理しやすくしてもまだ本番利用には不向きだと思いました。開発環境をサクッと構築したい時には便利です。
よって本番では、外部のロードバランサを使って公開するか、Ingressというクラスタ内部のロードバランサを使って公開する方法が有用ですが、今回は構築は実施しません。
(両者の違いについてはこちらが参考になりました。)

マニフェストを適用する

上記の通り操作してくるとマニフェストファイル構成は以下のようになっているはず。

┌ cm-file.yaml  
├ cm.yaml  
├ mattermost-db-deploy.yaml  
├ mattermost-db-service.yaml  
├ mattermost-deploy.yaml  
└ mattermost-service.yaml  

マニフェストファイルを適用して各種k8sオブジェクトを作成する

$ kubectl apply -f .

ブラウザからアクセスできることを確認するためにNodeのIP、Nodeに割り当てられたポート番号を調べます。

# NodeのIPアドレスを調べる
$ minikube ip
192.168.99.100

# NodePortに割り当てられたのポート番号を調べる
$ kubectl get svc mattermost
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
mattermost   NodePort   10.102.242.69   <none>        8065:31837/TCP   3m50s

PORT(s)のカラムをみると、2つのポート番号が表示されていますが、{アプリが待ち受けしているポート}:{Nodeに割り当てられたポート}を表しています。

よってhttp://192.168.99.100:31837でブラウザからアクセスできるはずです。

今回は以上です。

サクッと利用してみたいのであればk8sのマネージドサービスも一般的かもしれませんが、利便性の反面、内部の仕組みが隠蔽されて仕組みを理解する題材には向いていないかなと思いましてローカルにminikubeでk8s環境を立ててみました。今回の内容はまだまだ入り口かとは思いますが、実際にアプリケーションをデプロイすることを実践してみてk8sの足がかりになったかなと思います。

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

Cloud Runを試してみる

Cloud Runとは

Google Cloud Next '19 San Francisco で発表された、GCPの新サービス、
Cloud Runを試してみる。
コンテナを作成しデプロイするだけで、サーバレスで実行できるようになるらしい。
コンテナ上でアプリケーションが動くため、どんな言語で作成されたものでも実行可能。

公式チュートリアル

https://cloud.google.com/run/docs/quickstarts

Dockerイメージを作成する

以下の3ファイルを作成

requirements.txt
Flask==1.0.2
gunicorn==19.9.0
Dockerfile
FROM python:3.7

ENV PORT=8080
WORKDIR /usr/src/app

COPY requirements.txt ./
COPY app.py ./
RUN pip install --no-cache-dir -r requirements.txt

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app
app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
@app.route('/<id>')
def hello(word=World):
    return f'Hello {word}!!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))

ビルドして、GCRにプッシュ

PROJECT_ID=<YOUR_PROJECT>
IMAGE=cloud-run-sample

docker build -t gcr.io/${PROJECT_ID}/${IMAGE} .

gcloud docker -- push gcr.io/${PROJECT_ID}/${IMAGE}

デプロイ

GCPコンソールからCloud Runを選択、「CREATE SERVICE」を選択
先程ビルドしたコンテナイメージを選択し、サービス名、ロケーションを入力。
「未認証の呼び出しを許可」にチェックを入れ、作成。
デプロイが終わると、URLが割り当てられるので、ブラウザでアクセスし、
アプリケーションが動いていることが確認できる。

まとめ

コンテナさえあれば簡単にデプロイできる。
初めてアクセスするときは5~10秒くらいかかる。コンテナ起動の時間なのか?
Cloud Functionsとどう使い分けるべきか検証したい。

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