kakts-log

programming について調べたことを整理していきます

Rust: Error for copying String allocated memory to new variable.

When I write Rust code as below, it occurs error. I tried to print two same String by copying memory.

fn main() {
    let s1 = String::from("Hello");
    let s2 = s1;
    println!("{}, {}", s1, s2);
}
error[E0382]: use of moved value: `s1`
  --> src/main.rs:14:24
   |
13 |     let s2 = s1;
   |         -- value moved here
14 |     println!("{}, {}", s1, s2);
   |                        ^^ value used here after move
   |
   = note: move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait

error: aborting due to previous error

error: Could not compile `owner`.

The reason of this is arisen from Rust's memory management. In The Rust code, String pointer is assigned to two variables s1, s2.
If s2 is tried tobe copied allocated memory value of s1, s1 variable goes out of scope, it no longer be valid.
This is one of the mechanism of Rust's memory management called move .

So in this case, s1 is already moved to s2, it is invalid to use s1 in println!() .

Installing node.js v8.11.1 to centos 6.5 server.

Recently, Node.js v8.11.1 was released.
From this version, minimum compiler requirement(gcc) for Node.js had been updated to 4.9.4.

https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V8.md#8.11.1

In the centOS 6.5 server, default gcc package version was too old, so I had to update gcc version over 4.9.4 .

Installing devtoolset-4

To use newer gcc and other packages, Software Collections provides devtoolset for CentOS servers. Devtoolset-4 — Software Collections

In April 2018, devtoolset-4 is already ended its support, but in this post, I'll try to introduce how to install devtoolset-4.
There is also devtoolset-2 repository, but in this devtoolset-2, the version of gcc is 4.9.2. It's not applicable to node.js v8.11.1.

scl-utils package

First, to install devtoolset-4, it requires scl-utils package version above "20120927-11".
I had to set up SCL repository for centOS. repository base url is http://vault.centos.org/6.5/SCL/x86_64/

I created repository setting file to /etc/yum.repos.d/centos-scl.repo . The content of the file is as below.

[centos-scl]

name=centos-scl
baseurl=http://vault.centos.org/6.5/SCL/$basearch/
gpgcheck=0
enabled=0

After create this file, install scl-utils pakcage.

$ sudo yum install scl-utils --enablerepo=centos-scl

devtoolset-4 package

Next, set up new yum repository. mirror.centos.org provides a yum repository for Software collection packages. http://mirror.centos.org/centos/6/sclo/x86_64/rh/
In this repository, there are some versions of devtoolset. You can choose the version of it as you like.

Same as the previous chapter, it needs to set up yum repository setting. I created it to /etc/yum.repos.d/centos-devtools.repo

[centos-devtools]
name=centos-devtools
baseurl=http://mirror.centos.org/centos/6/sclo/x86_64/rh/
gpgcheck=0
enabled=0

After that, I can install some devtools-4's gcc packages for building node.js v8.11.1's native module.

$ sudo yum install devtoolset-4-gcc devtoolset-4-gcc-c++ devtoolset-4-binutils --enablerepo=centos-devtools

Finally, checking the scl list. If devtoolset-4 in the scl list, it's okay to use newer gcc.

$ scl -l

devtoolset-2
devtoolset-4

By enabling devtoolset-4, I was finally able to use newer gcc.

$ scl enable devtoolset-4 bash

$ gcc --version
gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)

Copyright (C) 2015 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO

warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

How to solve the yum ** http://mirror.centos.org/centos/6/SCL/x86_64/repodata/repomd.xml: [Errno 14] PYCURL ERROR 22 ** error in Centos6.5 server.

After installing centos-release-SCL yum package in CentOS 6.5 server, installing other yum package was failed. Error message is same as below.

$ sudo yum install libcurl
http://mirror.centos.org/centos/6/SCL/x86_64/repodata/repomd.xml: [Errno 14] PYCURL ERROR 22 - "The requested URL returned error: 404 Not Found"
Trying other mirror.
Error: Cannot retrieve repository metadata (repomd.xml) for repository: scl. Please verify its path and try again

The reason of this is about new yum repo setting file in /etc/yum.repos.d/ . If I install centos-release-SCL package, CentOS-SCL.repo file was created in /etc/yum.repos.d/ .

# CentOS-SCL.repo
#
# The Software Collections  ( SCL ) repository contains rpms for newer 
# software that can be installed alongside default versions
#
# Look at http://wiki.centos.org/AdditionalResources/Repositories/SCL
# for more details about how this repository works

[scl]
name=CentOS-$releasever - SCL
baseurl=http://mirror.centos.org/centos/$releasever/SCL/$basearch/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

In this file, baseurl is set to http://mirror.centos.org/centos/$releasever/SCL/$basearch/ . But this url might be already deprecated. For example, in this url. http://mirror.centos.org/centos/6.5/

There is only readme file in this repo.

To resolve this problem, I removed /etc/yum.repos.d/CentOS-SCL.repo

$ sudo rm /etc/yum.repos.d/CentOS-SCL.repo

And cleaned yum cache.

$ sudo yum clean all

After doing this, the probleam was resolved.

minikube start 時に [Error starting host: Error getting state for host: machine does not exist] が出た時の対処法

前提

  • macOS 10.11.6
  • kubectl v1.9.3
  • minikube v0.25.0

発生内容

ローカル環境でminikubeにより一度作った vmを削除後、 minikube start --vm-driver=virtualbox を実行すると以下のエラーがでる

[Error starting host: Error getting state for host: machine does not exist]

起動時にvmのホスト情報が取れていなくてエラーになる minikube/start.go at master · kubernetes/minikube · GitHub

さらに内部をみると vm driverのapiで、ドライバーの状態が取れなくてエラーになっている minikube/cluster.go at master · kubernetes/minikube · GitHub

virtualboxで起動されていたvmを削除したが、minikube内部で削除された状態が残っているものと思われる

解決策

minikube delete してローカルのkubernetes clusterを削除した上で,minikube startしなおすと再度minikube vmを立ち上げれるようになる

参考 minikube start - Error starting host, machine does not exist · Issue #459 · kubernetes/minikube · GitHub

Docker Swarm まとめ

概要

前記事(http://kakts-tec.hatenablog.com/entry/2018/02/12/220716)に引き続き, Docker公式ドキュメントのPart4 Swarmsの内容を整理します.

Part4 Swarms

Introduction

Part3ではPart2で作成したアプリケーションを取り上げ,Serviceを用いてproduction環境の定義を行い,プロセスのスケールアップも行いました.
Part4では,アプリケーションをクラスタ上にデプロイし,複数マシン上で実行させます.
マルチコンテナ,マルチマシンアプリケーションは複数のマシンをswarmと呼ばれるDockernizedされたクラスタにジョインすることで可能となります.

Understanding Swarm clusters

swarm はDockerを実行し,クラスタに参加するマシンのグループのことです.
クラスタにジョインしたあと,今までどおりdockerコマンドを使いますが,swarm manager によってクラスタ上で実行されます.
swarm内のマシンは物理マシンや仮想マシンです. swarmにジョイン後,それらのマシンはnodesと呼ばれます.

swarm manager はコンテナを実行するために複数のストラテジーを利用可能で,たとえば emptiest node と呼ばれるコンテナが一番起動されていないマシンを選んで起動する方式などがあります.
そしてglobal と呼ばれるストラテジーは, 各マシンが特定のコンテナを1つのみ持つことを保証するものです.
ユーザはcomposeファイル内でどのストラテジーを使うか定義できます.

swarm managerはswarm内でユーザのコマンドを実行できる唯一のマシンで, 他のマシンがworker としてswarmにジョインするのを認証します.
workerはキャパシティーを担保するもので, 他のマシンとやりとりする権限をもちません.

今までの章では,dockerをローカルマシン上でシングルホストモードで使用していました.
しかしDockerはswarmを使用できるswarmモードにも切り替えることができます.
swarmモードを有効にするということは,現在使用しているマシンをswarm managerにするということです.
モードの変更後, Dockerは現在使っているマシンのみというよりも,ユーザが管理するswarmクラスタ上でコマンドが実行されます.

Set up your swarm

swarmは複数のnodeで構成され,各nodeは物理マシンでも仮想マシンでも可能です. 基本的なコンセプトはシンプルで, docker swarm init を実行しswarm modeを有効にし,現在使っているマシンをswarm managerにした上で, 他のホスト上でdocker swarm join を実行させ,workerとしてswarmにジョインさせます.

Create a cluster

まず,クラスターを作成する前に,複数のVMマシンを立ち上げます. Virtualbox環境を用意した上で話しをすすめます.
まず,docker-machineコマンドを使ってマシンを作ります.

docker-machine create --driver virtualbox node01
docker-machine create --driver virtualbox node02

LIST THE VMS AND GET THEIR IP ADDRESSES

実行後 docker-machine ls で作成したマシンの状態を確認できます.

$ docker-machine ls
NAME     ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
node01   -        virtualbox   Running   tcp://192.168.99.100:2376           v18.02.0-ce   
node02   -        virtualbox   Running   tcp://192.168.99.101:2376           v18.02.0-ce

INITIALIZE THE SWARM AND ADD NODES

最初のマシンはmanagerとして稼働し,管理用コマンドを実行したり,swarmにジョインしたworkerの管理を行います.
2台目のマシンはworkerとなります.

docker-machine ssh コマンドでマシン名を指定するとVMに対してコマンドを実行できます.
ここではnode01に対してdocker swarm initを実行し,swarm managerにします.

$ docker-machine ssh node01 "docker swarm init --advertise-addr 192.168.99.100"
Swarm initialized: current node (q9gndi1k8qfwtbusob9jmav2j) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-4ow9k02pfkb84fyd3jdwke0r0p0qigiac7rutprt3thn5jzrgj-590v3ftz0e5225ibrn7klensx 192.168.99.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

注意点

Port2377と2376について

常にdocker swarm init と docker swarm joinは2377ポートに対して行います.  

docker-machine ls で表示される2366ポートはDockerのdaemonポートです. このポートに対して操作を行うとエラーになります.

先程のnode01に対するdocker swarm initを実行したときに,以下の文言が表示されました.
ここに書いてあるとおり, node01はswarm managerになったので,swarmに対してジョインさせたいときはdocker swarm joinを実行すると可能になります.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-4ow9k02pfkb84fyd3jdwke0r0p0qigiac7rutprt3thn5jzrgj-590v3ftz0e5225ibrn7klensx 192.168.99.100:2377

今回はnode02をworkerにしたいのでnode02に対して実行させます.

$ docker-machine ssh node02 "docker swarm join --token SWMTKN-1-4ow9k02pfkb84fyd3jdwke0r0p0qigiac7rutprt3thn5jzrgj-590v3ftz0e5225ibrn7klensx 192.168.99.100:2377"
This node joined a swarm as a worker

これでnode02をworkerに追加できました. node01上で確認するとnode01がswarm leaderになっているのがわかります.

$ docker-machine ssh node01 "docker node ls"
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
q9gndi1k8qfwtbusob9jmav2j *   node01              Ready               Active              Leader
s31768g3n99fev0sabf2i0q0g     node02              Ready               Active              

Deploy your app on the swarm cluster

一通りswarmに対する操作は終わりあとはPart3とほぼ同じ操作を行うのみです.
前述しましたが,注意点として, swarm managerであるnode01のみがdockerコマンドを実行でき,残りのworkerでは実行できません.

Configure a docker-machine shell to the swarm manager

今まで, Dockerコマンドを実行するのにdocker-machine ssh を使ってVMとやり取りしていました. 別のやり方として,docker-machine env を実行して,VM上のDocker daemonと,ユーザのローカルマシンのシェルからやり取りするための設定を行います.
このやり方は非常に便利で,なぜならローカル環境のdocker-compose.ymlを使うことができ,マシンに直接コピーせずともリモートでアプリケーションをデプロイできるからです.

さっそくdocker-machine env node01 を実行して見ます. これにより,node01に対する設定項目が出力されます.

$ docker-machine env node01
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/username/.docker/machine/machines/node01"
export DOCKER_MACHINE_NAME="node01"
# Run this command to configure your shell:
# eval $(docker-machine env node01)

出力結果に書いてあるとおりに実行すると設定が完了します.

eval $(docker-machine env node01)

docker-machine ls コマンドを実行することで,現在のシェルがどのノードに対してアクティブになっているのかを確認できます.

$ docker-machine ls
NAME     ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
node01   *        virtualbox   Running   tcp://192.168.99.100:2376           v18.02.0-ce   
node02   -        virtualbox   Running   tcp://192.168.99.101:2376           v18.02.0-ce

Deploy the app on the swarm manager

ここでnode01のマシンをswarm managerとして使うことができ,Part3で使ったdocker stack deploy コマンドとdocker-compose.yml でアプリケーションをデプロイできる状態になりました.
このコマンドは実行完了までに数秒かかり,デプロイしたものが利用可能になるまで時間がかかります.
docker service ps <service_name> をswarm managerで実行して全てのサービスがデプロイされていることを確認できます.

$ docker service ps getstartedlab_web
ID                  NAME                  IMAGE                     NODE                DESIRED STATE       CURRENT STATE                    ERROR               PORTS
r07ynn2v8bj7        getstartedlab_web.1   username/get-started:part2   node02              Running             Running less than a second ago                       
m3lg9lbr23xb        getstartedlab_web.2   username/get-started:part2   node01              Running             Running 1 second ago                                 
pt6ajvyvkbgv        getstartedlab_web.3   username/get-started:part2   node02              Running             Running less than a second ago                       
aftz97jyv5cq        getstartedlab_web.4   username/get-started:part2   node01              Running             Running 1 second ago                                 
k3vhukabiv5v        getstartedlab_web.5   username/get-started:part2   node02              Running             Running less than a second ago                       
vzr3ujd6hjif        getstartedlab_web.6   username/get-started:part2   node01              Running             Running 1 second ago                                 
neeh3npk9n7g        getstartedlab_web.7   username/get-started:part2   node02              Running             Running less than a second ago

これによりservicesのコンテナがnode01とnode02のそれぞれにデプロイされたことがわかります.

Accessing your cluster

これでnode01とnode02のIPアドレスからアプリケーションにアクセスできるようになりました.
作成したネットワークは2つのnodeとロードバランサーに共有されています. docker-machine ls でどちらかのnodeのipへアクセスしてリロードしてみてください.

今回は7つのレプリカを指定したのでアクセスするたびに7つのコンテナにランダムに振り分けられます.
node01とnode02のどちらに対してアクセスしても適切にロードバランシングされます.
これは,swarm内の各nodeがrouting meshに参加しているためです.
これはswarm内の特定のポートに対してデプロイされたserviceが,コンテナがどのようなnode上で動いていても常にポートを持つことを保証するためです.

Docker Servicesまとめ

概要

前記事

Docker containerまとめ - kakts-log

に引き続き Docker公式ドキュメントのPart3 Servicesの内容を整理します.

Part3 Services

Introduction

パート3では、アプリケーションのスケールを行い,ロードバランシングを有効にさせます.
これを行うために,アプリケーションのヒエラルキーの一段上のレベル,Serviceについて取り上げます.

  • Stack
  • Services
  • Container

About services

分散化されたアプリケーションにおいて,分散化された各ピースのことを"Services"と呼びます.
たとえば,もし動画のシェアリングサイトを考えたときに,おそらくアプリケーションはデータベースにアプリケーションを保存するServiceを含むのと,ユーザがアップロードしたあとにバックグラウンドで動画をトランスコードするServiceや,フロントエンドのServiceが考えられます.

Servicesは実際にはただの本番環境でのコンテナ群として扱われます.
単一のServiceは,1つのイメージを実行しますが,イメージをどのように実行するかを明文化します.
たとえば,どのポートを使うか,Serviceがキャパシティを担保するためにいくつのコンテナレプリカを実行するかなどです.
Serviceのスケーリングを行う場合は,コンテナの数を変更し,そのServiceに対して使うリソースを増やします.

Your first docker-compose.yml file

docker-compose.yml ファイルはYAML形式のファイルで,Dockerコンテナがプロダクション環境でどのように振る舞うかを定義します.

docker-compose.yml

docker-compose.yml というファイルを作成して,使っているディレクトリの直下に保存します.

version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: username/repo:tag
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"
    networks:
      - webnet
networks:
  webnet:

内容は上記になります.具体的には以下の内容でコンテナを起動するように指定しています.

  • Part2で使ったイメージをpullしてくる
  • webというService名で,5つのコンテナインスタンスを起動する. 各コンテナは最大でも10%のCPUリソースと50MBのRAMを使用します.
  • もしコンテナが落ちた場合すぐに再起動させる.
  • ホストマシンの80番ポートをwebのポート80に対応させる.
  • webのコンテナに対して,webnetと呼ばれるロードバランシングネットワークを介して80番ポートを共有させる. (内部的には,各コンテナは80番のエフェメラルポートとしてパブリッシュする)
  • webnetネットワークを初期設定で定義する.

Run your new load-balanced app

docker stack deploy コマンドを実行する前に,下記コマンドを実行します.

docker swarm init

詳細はPart4で解説します.

ここでdocker stack deployコマンドを実行します .

docker stack deploy -c docker-compose.yml getstartedlab

これにより,docker-compose.yml で指定した内容をもとにServiceが起動します.

docker service ls で,立ち上げたServiceの一覧を確認できます.

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                     PORTS
iji3jgsi3i80        getstartedlab_web   replicated          5/5                 username/get-started:part2   *:80->80/tcp

NAME項目をみると,指定したアプリ名がService名(web)の先頭に付加され,getstartedlab_webとなっているのがわかります.

ロードバランシングされるので,ホストマシンのブラウザでlocalhost:80でアクセスするとコンテナにアクセスされ,アクセス毎にHostnameが変わることを確認できます.

さらにdocker ps で実際に立ち上がったコンテナが5つあることを確認できます.

$ docker ps
CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS              PORTS               NAMES
c39d05ca95fe        username/get-started:part2   "python app.py"     7 seconds ago       Up 3 seconds        80/tcp              getstartedlab_web.3.xievdky2mkx38pl1foa68tzcg
002d8fe2434d        username/get-started:part2   "python app.py"     7 seconds ago       Up 3 seconds        80/tcp              getstartedlab_web.2.z17cyc4kcavu21o6cu2pxtjfl
a959c1870f87        username/get-started:part2   "python app.py"     7 seconds ago       Up 4 seconds        80/tcp              getstartedlab_web.1.xghoiespwuc5wu2oxqn52xxhh
eebff64dc8ac        username/get-started:part2   "python app.py"     7 seconds ago       Up 4 seconds        80/tcp              getstartedlab_web.4.y0vvq8sjj8xzau3meq98fbpfm
4ba7a3c03f56        username/get-started:part2   "python app.py"     7 seconds ago       Up 4 seconds        80/tcp              getstartedlab_web.5.a57ejflvl0k1ckpqs5jvu33v7

docker service ps ${service_name} でサービスに紐付いたコンテナのみを表示することもできます.

Scale the app

docker-compose.yml 内のreplicas項目を変更することで,アプリケーションをスケールできます.
変更した後,再度docker stack deploy コマンドを実行することで再起動できます.
今回はreplicasを7に変更した上で再起動します.

docker stack deploy -c docker-compose.yml getstartedlab_web

再起動後,コンテナが7つ起動しているのを確認できます.

$ docker container ls
CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS              PORTS               NAMES
ff8a37fa9377        username/get-started:part2   "python app.py"     18 seconds ago      Up 17 seconds       80/tcp              getstartedlab_web.6.umd3i06tcfq1jkeh64znr53uv
fc5150a8b9ee        username/get-started:part2   "python app.py"     18 seconds ago      Up 16 seconds       80/tcp              getstartedlab_web.7.q6kbemo6ghgjh7v45amsvcwzn
c39d05ca95fe        username/get-started:part2   "python app.py"     15 minutes ago      Up 15 minutes       80/tcp              getstartedlab_web.3.xievdky2mkx38pl1foa68tzcg
002d8fe2434d        username/get-started:part2   "python app.py"     15 minutes ago      Up 15 minutes       80/tcp              getstartedlab_web.2.z17cyc4kcavu21o6cu2pxtjfl
a959c1870f87        username/get-started:part2   "python app.py"     15 minutes ago      Up 15 minutes       80/tcp              getstartedlab_web.1.xghoiespwuc5wu2oxqn52xxhh
eebff64dc8ac        username/get-started:part2   "python app.py"     15 minutes ago      Up 15 minutes       80/tcp              getstartedlab_web.4.y0vvq8sjj8xzau3meq98fbpfm
4ba7a3c03f56        username/get-started:part2   "python app.py"     15 minutes ago      Up 15 minutes       80/tcp              getstartedlab_web.5.a57ejflvl0k1ckpqs5jvu33v7

Take down the app and the swarm

アプリケーションを停止する場合docker stack rmコマンドを実行します.

docker stack rm getstartedlab

実行後,Serviceが削除されていることを確認できます.

$ docker service ps getstartedlab_web
no such service: getstartedlab_web

swarmを停止する場合は以下のコマンドを実行します.

docker swarm leave --force

以上です. このようにDockerを使ったアプリケーションのスケールは非常に簡単です.