- 投稿日:2019-05-06T20:40:35+09:00
カンタン! Mac で 仮想環境構築(VirtualBox + Vagrant + CentOS 7)
1. はじめに
実際に仮想環境を構築しながら、自分が手順や知識を忘れない為に記事に残しています。
2. 仮想環境とは
仮想環境とは、パソコンやサーバーなどのハードウェア内で、仮想化の技術を使って創り出された仮想的な環境を意味します。
今回は、仮想化ソフトウェア(VirtualBox)と仮想マシンを構築するためのソフトウェア(Vagrant)を使って、私のパソコン(Mac)に、仮想的なパソコン(CentOS 7)を創り出します。
3. VirtualBox のインストール
こちらの記事を参考にインストールして下さい。
4. Vagrant のインストール
こちらの記事を参考にインストールして下さい。
5. Vagrant の操作
5 - 1. Box の追加
Boxとは、仮想マシンを作成する際に必要なOSのディスクイメージファイル等が入ったファイルの集まりで、例えて言えば、仮想マシンのテンプレート(雛形)です。
手順1. ターミナルを起動します。
手順2. ホームフォルダの直下に、下記のディレクトリを作成するコマンドを実行して、「MyVagrant」フォルダを作成します。
$ mkdir MyVagrant手順3. 下記のディレクトリを移動するコマンドを実行して、「MyVagrant」フォルダに移動します。
$ cd MyVagrant手順4. 下記のディレクトリを作成するコマンドを実行して、「CentOS7」フォルダを作成します。
$ mkdir CentOS7手順5. 下記のディレクトリを移動するコマンドを実行して、「CentOS7」フォルダに移動します。
$ cd CentOS7手順6. 下記の Box を追加するコマンドを実行します。
$ vagrant box add centos/7
下記のように、プロバイダを選択して下さいと表示されます。
$ vagrant box add centos/7 ==> box: Loading metadata for box 'centos/7' box: URL: https://vagrantcloud.com/centos/7 This box can work with multiple providers! The providers that it can work with are listed below. Please review the list and choose the provider you will be working with. 1) hyperv 2) libvirt 3) virtualbox 4) vmware_desktop Enter your choice:手順7. 今回は、VirtualBox を使っているので、「3」を入力して実行します。
Enter your choice: 3Box の追加に成功すると、下記のように表示されます。
==> box: Successfully added box 'centos/7' (v1902.01) for 'virtualbox'!手順8. 下記の Box を一覧表示させるコマンドを実行します。
$ vagrant box list下記のように追加した Box が一覧に表示されていれば、Box の追加は完了です。
$ vagrant box list centos/7 (virtualbox, 1902.01)5 - 2. Vagrant の初期化
手順1. 下記の Vagrant を初期化するコマンドを実行します。引数には、先ほど追加した Box(centos/7)を指定します。
$ vagrant init centos/7下記のように、Vagrant を起動する準備ができましたと表示されます。
$ vagrant init centos/7 ready to `vagrant up` your first virtual environment! Please read the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant.手順2. 下記のディレクトリやファイルの情報を表示するコマンドを実行します。
$ ls下記のように、「Vagrantfile」という設定ファイルが作成されていれば、Vagrant の初期化は完了です。
$ ls Vagrantfile5 - 3. Vagrant の起動
手順1. 先ほど作成した「Vagrantfile」ファイルが存在するディレクトリで、下記の Vagrant を起動するコマンドを実行します。VirtualBox を使って、仮想マシンが作成された後、Vagrant が起動します。
$ vagrant up手順2. 下記の仮想マシンの状態を確認するコマンドを実行します。
$ vagrant status
下記のように「running」と表示されていれば、Vagrant の起動は完了です。
起動している状態$ vagrant status Current machine states: default running (virtualbox) The VM is running. To stop this VM, you can run `vagrant halt` to shut it down forcefully, or you can run `vagrant suspend` to simply suspend the virtual machine. In either case, to restart it again, simply run `vagrant up`.下部の文章は、仮想マシンは実行中です。停止させるには、'vagrant halt'コマンドを実行して強制的にシャットダウンするか、'vagrant suspend'コマンドを実行して仮想マシンを一時停止させます。どちらの場合も、再起動するには、'vagrant up'コマンドを実行してください、というような内容です。
5 - 4. ログイン
手順1. 下記の仮想マシンにSSH接続するコマンドを実行します。
$ vagrant ssh
下記のように、「vagrant」ユーザーでログインができます。
[vagrant@localhost ~]$手順2. 下記の現在、操作しているディレクトリを確認するコマンドを実行します。
[vagrant@localhost ~]$ pwd下記のように、仮想マシン内のディレクトリを操作していることがわかります。
[vagrant@localhost ~]$ pwd /home/vagrant5 - 5. ログアウト
手順1. ログアウトする場合は、下記のコマンドを実行します。
[vagrant@localhost ~]$ exit下記のように、ログアウトができます。
[vagrant@localhost ~]$ exit logout Connection to 127.0.0.1 closed.5 - 6. Vagrant の停止
手順1. 下記の Vagrant を停止するコマンドを実行します。
$ vagrant halt下記のように、仮想マシンを正常にシャットダウンしようとしています...と表示されます。
$ vagrant halt ==> default: Attempting graceful shutdown of VM...手順2. コマンドが入力できるようになったら、下記の仮想マシンの状態を確認するコマンドを実行します。
$ vagrant status
仮想マシンが停止している場合は、下記のように表示されます。
停止している状態$ vagrant status Current machine states: default poweroff (virtualbox) The VM is powered off. To restart the VM, simply run `vagrant up`下部の文章は、仮想マシンを再起動するには'vagrant up'コマンドを実行して下さいと表示されています。
以上が、Mac で VirtualBox と Vagrant を使って仮想環境を構築する基本的な手順になります。
以下は、その他のよく使う操作の説明になります。
6. その他の操作
6 - 1. 仮想マシンの一時停止
手順1. 下記のコマンドで仮想マシンを一時停止できます。
$ vagrant suspend下記のように、仮想マシンの状態を保存して実行を中断しています...と表示されます。
$ vagrant suspend ==> default: Saving VM state and suspending execution...手順2. コマンドが入力できるようになったら、下記の仮想マシンの状態を確認するコマンドを実行します。
$ vagrant status
仮想マシンが一時停止している場合は、下記のように表示されます。
一時停止している状態$ vagrant status Current machine states: default saved (virtualbox) To resume this VM, simply run `vagrant up`.下部の文章は、仮想マシンを再開するには'vagrant up'コマンドを実行して下さいと表示されています。
6 - 2. 仮想マシンの再起動
手順1. 下記のコマンドで仮想マシンを再起動できます。
$ vagrant reload以前、ECサイトの開発案件にて、'vagrant reload'コマンドでは jQuery が正常に読み込まれないことがあったので、私は下記のコマンドで仮想マシンを再起動させています。
$ vagrant halt; vagrant up6 - 3. 仮想マシンの破棄
手順1. 下記のコマンドで仮想マシンを破棄できます。(Box は破棄されません。)
$ vagrant destroy6 - 3. Box の削除
手順1. 下記のコマンドで Box を削除できます。
$ vagrant box remove centos/76 - 4. Box のパッケージ化
手順1. 下記のコマンドで Box をパッケージ化できます。
$ vagrant package下記のように、「package.box」というファイルが作成されます。
$ ls Vagrantfile package.box「package.box」ファイルを指定して、下記のコマンドで Box を追加できます。
$ vagrant box add {box名} package.box開発メンバーに、自分の「package.box」ファイルを配布することで、同じ環境で開発を行うことができ、とても便利です。
6 - 5. SSH接続情報の確認
手順1. 下記のコマンドで SSH 接続情報の確認ができます。
$ vagrant ssh-config以上になります。
- 投稿日:2019-05-06T19:14:11+09:00
【これだけは】よく使う便利なツール【入れる】
インターネットの中には様々なツールがありますよね。
今日は、その中でよく使っているツールの紹介をします!キャプチャ
FastStone Capture (Windows)
https://www.vector.co.jp/soft/win95/art/se492849.html
Skitch - 撮る。描き込む。共有する (Mac)
どちらも直感的に使用できるUIで、使い勝手が良いです。
エビデンス取得に愛用しています^^差分表示
WinMerge (Windows)
http://winmerge.org/downloads/?lang=ja
FileMerge (Mac)
https://itunes.apple.com/jp/app/xcode/id497799835?mt=12
FileMergeはXcodeの機能の一部です。
ソースのコミット、レビュー時に活用しています。
リモートデスクトップ
TeamViewer
https://www.teamviewer.com/ja/
遠隔操作のツールです。
Windows→Mac、Mac→Windowsの操作にも対応しています。
何気に便利な機能。画像加工
Ralpha
https://forest.watch.impress.co.jp/library/software/ralpha/
画像のリサイズからロゴの透かし挿入まであらゆる加工が可能です。
フォトショより気軽にそれっぽい画像が作成できます。トラックパッド操作
BetterTouchTool (Mac)
https://folivora.ai/downloads/
トラックパッドジェスチャーでショートカットの設定ができます。
「新規タブで開く」や「タブ移動」などブラウジング操作などなど
いろいろなショートカットを設定して置くことができます。ぶっちゃけこれが一番使用しています!
便利なサイト
Thimble
https://thimble.mozilla.org/ja/
オンラインHTMLエディタです。
コード記入後に即、結果を確認できます。
カラーコード一覧表
http://www.netyasun.com/home/color.html
CSS、その他エクセル等のカラーコード調整に使用します。
なかなかコードだけで色をイメージすることって難しいですよねー
ネーミング
https://codic.jp/engine
変数名、メソッド名の手助けになります。
日本語→英語に変換し、キャメルケース等に変換してくれます。
メソッド名は、全てこれを使用しています。
URLエンコード・デコードフォーム
https://www.tagindex.com/tool/url.html
文字列をデコード、エンコードしてくれます。
パラメータとかエンコードされていることが多いので、デバッグ中によく使用します。
あとはChromeやeclipseとかもよく使用しますね。
もはや当たり前の存在になって来ていますので、省略しますm(_ _)mコメントでも普段使っているツールを教えていただけるとありがたいです。
Windowsの方が便利なツールが揃っている気が…?
- 投稿日:2019-05-06T18:36:48+09:00
Docker for mac のエラー「unauthorized: incorrect username or password.」対処法
Docker Desktop for mac をインストール後のPullで「unauthorized: incorrect username or password.」が発生。少しハマったので備忘として共有します。
Docker Hubより「pull」時にエラー発生
$docker run hello-world Unable to find image 'hello-world:latest' locally docker: Error response from daemon: Get https://registry-1.docker.io/v2/library/hello-world/manifests/latest: unauthorized: incorrect username or password. See 'docker run --help'.ID/PWDが異なるとの警告。原因はDockerHub登録時に利用したメールアドレスでログインしていたことでした。
メールアドレスで、DockerHubにログインする必要があります。[対応]Docker HubにユーザIDでログインする。
メールアドレスではなくユーザIDでログインしてください!!
確認
DockerHubからPull出来ることを確認。
$ docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 1b930d010525: Pull complete Digest: sha256:92695bc579f31df7a63da6922075d0666e565ceccad16b59c3374d2cf4e8e50e Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with:
- 投稿日:2019-05-06T15:37:51+09:00
Pythonでオリジナルのコマンドを実装してみる【後編】
前回の続きです。
【前編】
https://qiita.com/K_Takata/items/3c0e632db7b662f88f57こちらの記事で自動生成されているコマンドラインの起点……
jupyter.py#!/anaconda3/bin/python # -*- coding: utf-8 -*- import re import sys from jupyter_core.command import main if __name__ == '__main__': sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) sys.exit(main())の生成方法についてすっ飛ばしていたのですが、結構重要なポイントなのでこちらで解説させていただきます。
目標
前回と同様です。
macまたはLinuxのコマンドラインで$ MyCommandと打ち込むと
ジャンプで連載中のチェンソーマンが好きと出力されるようになる。
$ MyCommand --helpと打ち込むと、
ジャンプで連載中のチェンソーマンをダイレクトマーケティングするコマンドと、MyCommandの説明が出力される。
↑こちらのコマンドの起点を自動生成してみましょう。
ついでに後半でちょっと複雑なコマンドを作ってみましょう。よくわかる?解説
ローカルにテキトーにcloneしてくれや!
https://github.com/kizashitakata/MyCommandよくわからなかったらテキトーに参考にしながら作ってください。
解説しますね。構造はこんな感じです。
setup.pyを見てみましょう。
├── App │ ├── __init__.py │ ├── command1.py │ └── command2.py ├── README.md └── setup.pysetup.pyfrom setuptools import setup, find_packages setup( name='MyCommand', version='0.1.0', entry_points={'console_scripts': ['MyCommand = App.command1:main']}, install_requires=[ 'click' ], packages=find_packages() )今回必要な最低限のみ記載しています。
nameとversionは実際にPyPIにアップして世界中のみんなに使ってもらう際に重要になるのですが、自分で使う分にはテキトーで大丈夫です。PyPIにアップする際にテキトーなバージョンでアップすると後で痛い目に会うので注意しましょう。
今回の内容で一番重要なのが
entry_points
の部分で、ここにコマンドの起点を定義します。
後々わかるので大丈夫です。
install_requires
はなんとなく分かると思いますが、依存モジュールで、ここに定義しておけば後はinstall時になんとなく一緒に持ってきてくれます。今回は
ワイ推奨パッケージ便利なコマンドラインパーサのclickを使っているので、依存モジュールとして定義しています。
packages=find_packages()
は、__init__.py
があるフォルダをパッケージとして認識するために必要です。
……ちょっとややこしいですね。ディレクトリ構造に戻りますが
├── App │ ├── __init__.py │ ├── command1.py │ └── command2.py ├── README.md └── setup.pyこの
__init.py__
は、見ていただければ分かるのですが空ファイルです。
何のためにこの世に存在しているのかというと、"App" フォルダがパッケージだよという証明……みたいなものです。さっきの
entry_points={'console_scripts': ['MyCommand = App.command1:main']}
の部分での指定は「Appパッケージのcommand1.pyのmainメソッドがコマンドの起点ですよー」くらいの意味です。
「重要なフォルダには__init.py__
を用意するんやで」 くらいの認識でもOKです。ということでcommand1.pyを見てみましょう。
command1.pyimport click @click.command(help='ジャンプで連載中のチェンソーマンをダイレクトマーケティングするコマンド') def main(): click.echo('ジャンプで連載中のチェンソーマンが好き') pass前編の実装よりめっちゃシンプルになりましたね。
それもそのはず、
$ MyCommand --help
の出力内容がclickライブラリの標準機能にまとめられてスッキリシンプルになりました。出力もちょっと豪華になります。
$ mycommand --help Usage: mycommand [OPTIONS] ジャンプで連載中のチェンソーマンをダイレクトマーケティングするコマンド Options: --help Show this message and exit.ちなみに前回の実装方法にせよ今回の実装方法にせよ、コマンドは大文字でも小文字でもどっちでもOKです。今回は小文字で統一します。
さて、いよいよ。
どうやってこいつをコマンドとして自動生成するのか。ローカルでsetup.pyのあるディレクトリにcdしたあと、以下のように打ち込むだけです。
$ pip install ..はカレントディレクトリの意味なので、要するにpip installで指定のディレクトリにあるsetup.pyを叩いています。
pip install 〇〇 は便利なもので、PyPIにあるパッケージを指定するとPyPIから持ってきてくれますし、ローカルディレクトリのsetup.pyのあるディレクトリを指定すると、よしなにパッケージを展開してくれます。
コマンド実行後、mycommandが使えるようになってるはずです。
簡単ですね。ちょっとだけ応用
mycommand one
mycommand two
みたいに、コマンドごとに処理を変えたいってこともありますよね?
夕飯にカレーが食べたくなるくらいの頻度であるはずです。
setup.py
の
entry_points={'console_scripts': ['MyCommand = App.command1:main']}
のcommand1の部分をcommand2に書き換えてみましょう。それから改めて、
$ pip install .してみてください。
command2の内容はこんな感じです。
command2.pyimport click @click.group() def main(): pass @main.command() def one(): click.echo('処理1') @main.command() def two(): click.echo('処理2')
チェンソーマン絡ませるとややこしいのでめっちゃ単純にしました。
これだけです。これだけで、$ mycommand one 処理1$ mycommand two 処理2実装完了です。
夢が広がりますね。まとめ
pipは優秀。
以上です。お読みいただきありがとうございました。
参考
Pythonでグローバルコマンドを含んだパッケージを作る
https://qiita.com/fetaro/items/bb0eb8292127b5d1e9a8Python: コマンドラインパーサの Click が便利すぎた
https://blog.amedama.jp/entry/2015/10/14/232045
- 投稿日:2019-05-06T14:56:13+09:00
[Mac]Zshでoh-my-zshからPreztoに切り替える
はじめに
シェル環境はZsh派ということもあり、これまで環境をイイ感じに構築してくれる oh-my-zsh を入れていました。
が、oh-my-zsh インストール後、環境設定もほぼデフォルトの状態で使用。
メンテナンスも満足にしておらず、当時のインストール時の備忘録も残さないまま、勢いで入れてそのままズルズル使用していたので、一発奮起して Prezto に乗り換えてみます。
Prezto - Instantly Awesome Zsh先人の知恵でたくさん記事があります。参考にさせていただきました。
https://blog.andooown.dev/post/2018/02/prezto/
https://qiita.com/Angelan1720/items/60431c85592fe90fcdd5
https://dev.classmethod.jp/tool/zsh-prezto/oh-my-zsh や Prezto ってそもそも何なの
oh-my-zsh や Prezto は、Zshでラクに環境構築を行うためのフレームワークです。
一から自分で設定することもできますが、こういったものを利用することで、比較的手軽に環境を構築することが可能になります。oh-my-zsh はオワコンで古い!とかいろんな意見を見ますが、依然人気は人気みたい。機能豊富だしいろいろできるもんね。
9 Best ZSH configuration frameworks as of 2019 - Slant前提条件
今回の自分の環境です。
この環境下で Prezto に切り替えていきます。
- ターミナル: iTerm2 を利用
- Homebrew/Homebrew Cask によるパッケージ管理
- oh-my-zsh 適用済み
- Zsh は Homebrew でインストール済み
完全クリーンな状態から Prezto をインストールする場合
概ね以下のような手順になるかと思います。
- Homebrew をインストール (入っていない場合)
- Zsh をインストール
Homebrew の使用に関しては好みがあると思うので、必須ではないです
前段階における注意点
.zshrc などにカスタムで環境設定を入れている場合は既存のものを流用してもいいかも。
わたしはそこまで環境設定を追加していなかったので、完全にリプレースしました。ただ有事の場合にロールバックができるように、念のため、設定ファイルとヒストリはバックアップを取っておきます。
-> % mkdir bkdir && mv .zsh* bkdir -> % ll -A bkdir total 632 -rw------- 1 user staff 309K 5 6 10:36 .zsh_history -rw-r--r-- 1 user staff 2.9K 10 4 2018 .zshrc切り替え手順
oh-my-zsh のアンインストール
アンインストールはコマンドがあります。README参照。
-> % uninstall_oh_my_zsh Are you sure you want to remove Oh My Zsh? [y/N] y Removing ~/.oh-my-zsh Looking for original zsh config... Switching back to bash Changing shell for user. Password for user: Thanks for trying out Oh My Zsh. It's been uninstalled.アンインストールが完了しました。
ターミナルを再起動すると、 bash になってます。$ echo $SHELL /bin/bashPrezto のインストール
zshに切り替え。
$ zsh
Prezto のREADMEに書いてあるように、リポジトリをcloneしてきます。
$ git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"以下のコマンドを実行すると、各種設定ファイルのシンボリックリンクが生成されます。
この時点ですでに存在しているファイルがあると、そのファイルに関してはリンクが生成されません。$ setopt EXTENDED_GLOB for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}" donelrwxr-xr-x 1 user staff 37 5 6 11:01 /Users/userDir/.zlogin -> /Users/userDir/.zprezto/runcoms/zlogin lrwxr-xr-x 1 user staff 38 5 6 11:01 /Users/userDir/.zlogout -> /Users/userDir/.zprezto/runcoms/zlogout lrwxr-xr-x 1 user staff 40 5 6 11:01 /Users/userDir/.zpreztorc -> /Users/userDir/.zprezto/runcoms/zpreztorc lrwxr-xr-x 1 user staff 39 5 6 11:01 /Users/userDir/.zprofile -> /Users/userDir/.zprezto/runcoms/zprofile lrwxr-xr-x 1 user staff 37 5 6 11:01 /Users/userDir/.zshenv -> /Users/userDir/.zprezto/runcoms/zshenv lrwxr-xr-x 1 user staff 36 5 6 11:03 /Users/userDir/.zshrc -> /Users/userDir/.zprezto/runcoms/zshrc.zshrc の設定を流用したい場合
いったん既存ファイルは退避しておいて、差分だけをあとから Prezto の .zshrc に追記する形がいいかも。
試しにdiff取ってみましたが、なんだこれ。。
Prezto は超絶シンプルすぎる環境設定。
中略部分は何十行も oh-my-zsh の設定が入ってる部分です。
やっぱり oh-my-zsh はオーバースペックすぎたかな。あと .zshrc にベタで書き込まれるパラメーターが多い。
oh-my-zsh のパラメーターファイルみたいなのがどっかにあって、それをincludeするとシンプルになりそうな気がする (主観です$ diff -u ~/bk_zsh/.zshrc ~/.zshrc --- /Users/user/bk_zsh/.zshrc 2018-10-04 13:38:32.000000000 +0900 +++ /Users/user/.zshrc 2019-05-06 10:53:24.000000000 +0900 @@ -1,92 +1,13 @@ -# Path to your oh-my-zsh installation. -export ZSH=/Users/user/.oh-my-zsh - -# Set name of the theme to load. -# Look in ~/.oh-my-zsh/themes/ -# Optionally, if you set this to "random", it'll load a random theme each -# time that oh-my-zsh is loaded. -ZSH_THEME="candy" ・・・ 中略 ・・・ +# Executes commands at the start of an interactive session. +# +# Authors: +# Sorin Ionescu <sorin.ionescu@gmail.com> +# +# Source Prezto. +if [[ -s "${ZDOTDIR:-$HOME}/.zprezto/init.zsh" ]]; then + source "${ZDOTDIR:-$HOME}/.zprezto/init.zsh" +fi +# Customize to your needs...インストールが完了したので、ログインシェルを Homebrew の Zsh に変更し、ターミナルを再起動します。
$ chsh -s /usr/local/bin/zsh補足:ログインシェル変更時のエラー
ログインシェルを変更する時に以下のように
non-standard shell
とエラーが出てしまう場合。
/etc/shells に Homebrew の Zsh のパスを追記することでエラーを解消することができます。$ chsh -s /usr/local/bin/zsh Changing shell for user. Password for user: chsh: /usr/local/bin/zsh: non-standard shell/etc/shells# List of acceptable shells for chpass(1). # Ftpd will not allow users to connect who are not using # one of these shells. /bin/bash /bin/csh /bin/ksh /bin/sh /bin/tcsh /bin/zsh /usr/local/bin/zsh // Homebrew の Zsh のパスを追記再起動後にシェルが変更されていることを確認します。
~ ❯❯❯ echo $SHELL /usr/local/bin/zshoh-my-zsh で入ってたaliasのバックアップ忘れた…と思ったけど、 Prezto インストール後のalias確認したら普段よく使うコマンドの短縮形は入ってるから問題なさそう
テーマの設定
さて、肝心のテーマですが、Prezto にはpromptコマンドというものがあり、オプション -p をつけることでテーマのプレビューが表示されます。
~ ❯❯❯ prompt -p
powerlineの人をけっこう見かけるのでpowerlineが人気なのかな。
でもわたしはparadoxにします。
デフォルトがsorinになっているので、 .zpreztorc を編集してコメントアウトor上書きします。~/.zpreztorc#zstyle ':prezto:module:prompt' theme 'sorin' zstyle ':prezto:module:prompt' theme 'paradox'どのようなテーマがあるかはここを見るとわかりやすいかも。
Customizing Your Prezto Prompt - Mike Bussテーマ適用時の注意点
上記記事のNoteに
you’ll need a Powerline-patched font.
と書いてある通り、paradoxをテーマとして適用する時は、Powerline用のフォントを使わないといけないみたいです。Powerline用のフォントについてはこちら。
GitHub - powerline/fonts: Patched fonts for Powerline users.Powerline用のフォントの適用
ということで、わたしは Source Code Pro を選択しました。
フォントのインストール方法はgit clone
だったり諸方法あるのですが、わたしは brew-cask-fonts が入っている環境なので、これを使ってインストールします。❯ brew cask info font-source-code-pro-for-powerline [12:28:41] font-source-code-pro-for-powerline: latest https://github.com/powerline/fonts/tree/master/SourceCodePro Not installed From: https://github.com/Homebrew/homebrew-cask-fonts/blob/master/Casks/font-source-code-pro-for-powerline.rb ・・・以下略・・・ ❯ brew cask install font-source-code-pro-for-powerlineインストールできたら、 iTerm2 のフォントの設定で Source Code Pro for Powerline を選択して完了です。
おわりに
とりあえずこれで使ってみて、もうちょっと便利にしたいなーと思ったら適宜調整していきます。
あと oh-my-zsh の残骸もお掃除しないと…
- 投稿日:2019-05-06T14:16:30+09:00
iPhoneで撮影した画像(*.HEIC)をjpgやpngに一括変換する
iPhoneで撮影した画像(*.HEIC)をjpgやpngに一括変換する
環境: macOS Mojave (10.14.4)
一個の場合
以下で出来ます。
$ sips --setProperty format jpeg input.heic --out output.jpgただこれ、ワイルドカード使えないんですよね(´・ω・`)
複数の場合
最新版のImageMagickを使って一括変換できます。
mogrify -format jpg -quality 80 *.HEICImageMagickでエラーが出た時の対処法
ImageMagickで変換できるかテスト
$ mogrify -format png *.HEIC mogrify: no decode delegate for this image format `HEIC' @ error/constitute.c/ReadImage/556.エラーが出た。バージョンを確認する。
$ convert -version Version: ImageMagick 7.0.8-24 Q16 x86_64 2019-01-18若干古い
ImageMagickを入れ直します。$ brew reinstall imagemagick かなり時間がかかる $ convert -version Version: ImageMagick 7.0.8-43 Q16 x86_64 2019-05-03 新しくなったこのバージョンでは成功しました(`・ω・´)ゞ
サンプル集
pngへの変換
$ mogrify -format png *.HEICiPhoneで撮影した画像ですとファイルサイズは8MBほどになります。
jpegへの変換(品質80%)
$ mogrify -format jpg -quality 80 *.HEIC品質を落としてjpegに変換するとファイルサイズは2MBほどになりました。
jpegへの変換(品質80%、画像サイズ縮小)
$ mogrify -format jpg -quality 80 -resize 25% *.HEICさらに画像サイズが大きいので縦x横ともに1/4のサイズにすると約110KBになりました。画像サイズは1008x756。
まとめ
一括変換する時はImageMagickが便利です(`・ω・´)ゞ
ImageMagickなのでUbuntuでも使えると思います。
- 投稿日:2019-05-06T13:18:07+09:00
一足遅れて Kubernetes を学び始める - 07. workloads その3 -
ストーリー
- 一足遅れて Kubernetes を学び始める - 01. 環境選択編 -
- 一足遅れて Kubernetes を学び始める - 02. Docker For Mac -
- 一足遅れて Kubernetes を学び始める - 03. Raspberry Pi -
- 一足遅れて Kubernetes を学び始める - 04. kubectl -
- 一足遅れて Kubernetes を学び始める - 05. workloads その1 -
- 一足遅れて Kubernetes を学び始める - 06. workloads その2 -
- 一足遅れて Kubernetes を学び始める - 07. workloads その3 -
- 一足遅れて Kubernetes を学び始める - 08. discovery&LB その1 -
前回
一足遅れて Kubernetes を学び始める - 06. workloads その2 -にて、DaemonSetとStatefulSet(一部)を学習しました。今回は、StatefulSetの続きとJob,CronJobを学習します。
StatefulSet
sample-statefulset.yamlapiVersion: apps/v1 kind: StatefulSet metadata: name: sample-statefulset spec: serviceName: sample-statefulset replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80 volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: - ReadWriteMany storageClassName: managed-nfs-storage resources: requests: storage: 1Gi永続的にデータが保存されるかどうか確認します。
pi@raspi001:~/tmp $ k apply -f sample-statefulset.yaml pi@raspi001:~/tmp $ k exec -it sample-statefulset-0 -- df -h Filesystem Size Used Avail Use% Mounted on ... 192.168.3.35:/home/data/default-www-sample-statefulset-0-pvc-* 15G 1.1G 13G 8% /usr/share/nginx/html ... pi@raspi001:~/tmp $ k exec -it sample-statefulset-0 touch /usr/share/nginx/html/sample.htmlsample.htmlというファイルを作りました。こちらが消えるかどうか確認します。
pi@raspi001:~/tmp $ k delete pod sample-statefulset-0 pi@raspi001:~/tmp $ k exec -it sample-statefulset-0 ls /usr/share/nginx/html/sample.html /usr/share/nginx/html/sample.htmlpodを消してセルフヒーリングで復活した後、確認すると、sample.html残っています。
pi@raspi001:~/tmp $ k delete -f sample-statefulset.yaml pi@raspi001:~/tmp $ k apply -f sample-statefulset.yaml pi@raspi001:~/tmp $ k exec -it sample-statefulset-0 ls /usr/share/nginx/html/sample.html /usr/share/nginx/html/sample.htmlこちらも残っていますね。OKです。
スケーリング
StatefulSetでは、スケールアウトするときは、インデックスが小さいものから増えていきます。
逆にスケールインするときは、インデックスが大きいものから削除されていきます。
また、1つずつ増減します。そのため、一番始めに作られるPodは、一番最後に削除されることになります。
試してみます。pi@raspi001:~ $ k get pod | grep sample-statefulset sample-statefulset-0 1/1 Running 1 10h sample-statefulset-1 1/1 Running 1 10h sample-statefulset-2 1/1 Running 1 10h pi@raspi001:~/tmp $ vim sample-statefulset.yaml # replica:3→4 pi@raspi001:~/tmp $ k apply -f sample-statefulset.yaml pi@raspi001:~/tmp $ k get pod | grep sample-statefulset sample-statefulset-0 1/1 Running 1 10h sample-statefulset-1 1/1 Running 1 10h sample-statefulset-2 1/1 Running 1 10h sample-statefulset-3 0/1 ContainerCreating 0 6s pi@raspi001:~/tmp $ vim sample-statefulset.yaml # replica:4→2 pi@raspi001:~/tmp $ k apply -f sample-statefulset.yaml pi@raspi001:~/tmp $ k get pod | grep sample-statefulset sample-statefulset-0 1/1 Running 1 10h sample-statefulset-1 1/1 Running 1 10h sample-statefulset-2 1/1 Running 1 10h sample-statefulset-3 0/1 Terminating 0 2m4s pi@raspi001:~/tmp $ k get pod | grep sample-statefulset sample-statefulset-0 1/1 Running 1 10h sample-statefulset-1 1/1 Running 1 10h sample-statefulset-2 0/1 Terminating 0 10h期待通りですね。1つずつではなく、並列して作成したい場合は、spec.podManagementPolicyをparallelにすれば実現できます。
アップデート戦略
戦略は2通りあり、OnDeleteとRollingUpdateがあります。前者は、削除された(マニュフェスト更新ではなく、delete)タイミングに更新され、後者は、即時更新します。StatefulSetの更新では、アップデート中の過不足分の調整(maxUnavailable, maxSurge)は一切できません。また、partitionというフィールドのによって、どのインデックス以降を更新するかを調整することもできます。これは、ステートフルならではの機能です。
Deploymentでは試してませんでしたが、こちらで試してみようと思います。デフォルトの戦略はRollingUpdateです。これは何度も動作して確認できているので、OnDeleteを試そうと思います。(partitionは置いとく)
sample-statefulset.yaml... spec: updateStrategy: type: OnDelete ... template: spec: containers: - name: nginx-container image: nginx:1.13 ...アップデート戦略をOnDeleteにし、nginxイメージを1.12から1.13に更新しました。
pi@raspi001:~/tmp $ k delete -f sample-statefulset.yaml pi@raspi001:~/tmp $ k apply -f sample-statefulset.yaml pi@raspi001:~/tmp $ k describe pod sample-statefulset-0 | grep "Image:" Image: nginx:1.12 pi@raspi001:~/tmp $ k delete pod sample-statefulset-0 pi@raspi001:~/tmp $ k get pod | grep sample-statefulset sample-statefulset-0 0/1 ContainerCreating 0 5s sample-statefulset-1 1/1 Running 0 2m59s pi@raspi001:~/tmp $ k describe pod sample-statefulset-0 | grep "Image:" Image: nginx:1.13期待通りですね。明示的にpodを削除すればnginxが更新されました。
Job
一度限りの処理を実行させるリソース。
replicaSetのように複製ができる。
バッチ処理に向いている。10秒sleepするだけのjobを実行してみます。
sample-job.yamlapiVersion: batch/v1 kind: Job metadata: name: sample-job spec: completions: 1 parallelism: 1 backoffLimit: 10 template: spec: containers: - name: sleep-container image: nginx:1.12 command: ["sleep"] args: ["10"] restartPolicy: Neverpi@raspi001:~/tmp $ k apply -f sample-job.yaml pi@raspi001:~/tmp $ k get pod NAME READY STATUS RESTARTS AGE sample-job-d7465 0/1 Completed 0 3m17s pi@raspi001:~/tmp $ k get job NAME COMPLETIONS DURATION AGE sample-job 1/1 27s 4m8sjobの実行が終わると、podが消えていますね。そして、jobのCOMPLETIONSが1/1になっているので正常終了したみたいです。逆に正常終了しなかった場合、restartPolicyに沿って再実行することになります。種類としてNeverとOnFailureがあります。Neverは、新規にPodを作って再実行、OnFailureは、既存Podを使って再実行するそうです。ただし、データ自体は消失することになるので、ご注意下さい。
completionsは目標成功数で、parallelismは並列数、backoffLimitは失敗許容値です。
目的に合う設定にすれば良いですね。
また、completionsを未指定にするとjobを止めるまでずっと動き続けます。backoffLimitを未指定にすると6回までとなります。んー、特に興味が惹かれることもなく、終わります。笑
CronJob
Jobをスケジュールされた時間で実行するリソース。
DeploymentとReplicaSetの関係と似ていて、Cronjobがjobを管理する。1分毎に50%の確率で成功するjobを用意して、試してみます。
sample-cronjob.yamlapiVersion: batch/v1beta1 kind: CronJob metadata: name: sample-cronjob spec: schedule: "*/1 * * * *" concurrencyPolicy: Allow startingDeadlineSeconds: 30 successfulJobsHistoryLimit: 5 failedJobsHistoryLimit: 3 suspend: false jobTemplate: spec: completions: 1 parallelism: 1 backoffLimit: 1 template: spec: containers: - name: sleep-container image: nginx:1.12 command: - "sh" - "-c" args: # 約50%の確率で成功するコマンド - "sleep 40; date +'%N' | cut -c 9 | egrep '[1|3|5|7|9]'" restartPolicy: Neverpi@raspi001:~/tmp $ k apply -f sample-cronjob.yaml pi@raspi001:~/tmp $ k get all NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/sample-cronjob */1 * * * * False 0 <none> 9s時間がくるまで、job,podは作成されないようです。
数分待ってみました。pi@raspi001:~/tmp $ k get all NAME READY STATUS RESTARTS AGE pod/sample-cronjob-1557115320-dsdvg 0/1 Error 0 2m18s pod/sample-cronjob-1557115320-qkgtp 0/1 Completed 0 87s pod/sample-cronjob-1557115380-r57sw 0/1 Completed 0 78s pod/sample-cronjob-1557115440-2phzb 1/1 Running 0 17s NAME COMPLETIONS DURATION AGE job.batch/sample-cronjob-1557115320 1/1 105s 2m18s job.batch/sample-cronjob-1557115380 1/1 52s 78s job.batch/sample-cronjob-1557115440 0/1 17s 17s NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/sample-cronjob */1 * * * * False 1 20s 3m12s名前の命名ルールがあるので、どう関連しているのか一目瞭然ですね。
Podが残っているのは、failedJobsHistoryLimitとsuccessfulJobsHistoryLimitの値の影響ですね。
logで確認できるように残しておくそうですが、ログ収集基盤に集約した方が良いとも言われています。途中で止めたいときは、spec.suspendをtrueにすることで実現可能になります。
同時実行する制限として、concurrencyPolicyがあり、Allow,Forbid,Replaceがあります。
Allowは、特に制限しない。
Forbidは、前のjobが終わらない限り実行しない。
Replaceは、前のjobを削除し、jobを実行する。遅延がどのぐらい許容できるかは、startingDeadlineSecondsで指定します。
こちらも、特に何事もなく終わりました。笑
お片付け
pi@raspi001:~/tmp $ k delete -f sample-statefulset.yaml -f sample-job.yaml -f sample-cronjob.yaml pi@raspi001:~/tmp $ k delete pvc www-sample-statefulset-{0,1,2,3}終わりに
ようやく、workloadsが終わりました。最後はざっくり進めてしまった感がありました。
次回はこちらです。
- 投稿日:2019-05-06T10:56:47+09:00
mac (Mojave) に DNS サーバを構築する際の覚書
目的
macOS Mojave に brew を用いてローカルネットワーク用 DNS (bind) サーバを構築した際の覚書を記載する
環境
- PC : Mac mini (Late 2014)
- OS : macOS Mojave 10.14.2
- Homebrew : 1.9.0
- インストールする bind : stable 9.12.3-P1 (bottled)
構築手順
Homebrew で DNS (bind) をインストールする
$ brew search bind $ brew info bind $ brew install bindインストール後の状態確認
$ sudo brew services list # bind の動作状態を確認する $ sudo brew services stop bind # started 状態ならば一旦停止させるメイン設定ファイル (/usr/local/etc/named.conf) を設定する
options ステートメントや正引き設定や逆引き設定を記述する
# ex) ... options { directory "/usr/local/var/named"; # ゾーンファイルを格納するディレクトリ /* * If there is a firewall between you and nameservers you want * to talk to, you might need to uncomment the query-source * directive below. Previous versions of BIND always asked * questions using port 53, but BIND 8.1 uses an unprivileged * port by default. */ // query-source address * port 53; version "Unknown DNS Server"; # バージョン表示 allow-query { localhost; localnets; }; # 問い合わせを受け付けるホスト allow-transfer { none; }; # ゾーン転送を許可するホスト recursion yes; # 再起問い合わせを受け付けるか forwarders { 192.168.0.???; }; # 問い合わせの回送先 DNS サーバ (ルータなどを指定) listen-on-v6 { none; }; # IPv6 を受け付けるか }; ... # sample.net ドメインの正引き設定 zone "sample.net" IN { type master; file "sample.net.zone"; }; # sample.net ドメインの逆引き設定 zone "0.168.192.in-addr.arpa" IN { type master; file "0.168.192.zone"; };ゾーンファイルを設定する
directory に指定したパス (/usr/local/var/named) 配下に,
* 正引き用 : sample.net.zone
* 逆引き用 : 0.168.192.zone
ファイルをそれぞれ作成する# sample.net.zone (正引き) の設定方法例 $TTL 86400 # 他の DNS サーバがゾーンデータをキャッシュに保存していく時間 $ORIGIN sample.net. # ドメイン名が明治されていないレコードで補完するドメイン名 # SOA はゾーンに関する基本的な情報を記述 # [書式] # 名前 IN SOA <DNSサーバ> <メールアドレス> (serial;refresh;retry;expire;negative TTL) # @ はそのドメイン自身を表す @ IN SOA <DNSサーバ名>.sample.net. root.sample.net. ( 2019050601 ; serial (変更日+バージョンとしている) 3H ; refresh (3時間) 15M ; retry (15分) 1D ; expiry (1日) 1D ) ; minimum (1日) # DNS サーバを FQDN で指定する @ IN NS <DNSサーバ名>.sample.net. # ホスト名に対する IP アドレスを指定 <DNSサーバ名>.sample.net. IN A 192.168.0.???# 0.168.192.zone (逆引き) の設定方法例 $TTL 86400 $ORIGIN 0.168.192.in-addr.arpa. @ IN SOA <DNSサーバ名>.sample.net. root.sample.net. ( 2019050601 ; Serial 3H ; Refresh 15M ; Retry 1D ; Expire 1D ) ; Minimum IN NS <DNSサーバ名>.sample.net. # IP アドレスに対するホスト名を記述する ???.0.168.192.in-addr.arpa. IN PTR <DNSサーバ名>.sample.net.記述方式が正しいか文法チェックする
- named.conf のチェック方法例
$ /usr/local/sbin/named-checkconf named.conf
- ゾーンファイルのチェック方法例
# 正引きの場合 $ /usr/local/sbin/named-checkzone sample.net sample.net.zone ... OK# 逆引きの場合 $ /usr/local/sbin/named-checkzone 0.168.192.in-addr.arpa. 0.168.192.zone ... OKbind を起動する
$ sudo brew services start bind $ sudo brew services listその他
DHCP サーバの DNS を構築したマシンにする etc
- 投稿日:2019-05-06T05:17:52+09:00
初めてmacでsshキーを作る
初めての場合
$ssh-keygen -t rsaこれで~/.sshに
秘密鍵id_rsaと公開鍵id_rsa.pubが出来る
ssh認証キーを貼り付けてくれとか頼まれた場合は$pbcopy .ssh/id_rsa.pubcatで出してコピペする方法もある。
- 投稿日:2019-05-06T00:59:51+09:00
一足遅れて Kubernetes を学び始める - 06. workloads その2 -
ストーリー
- 一足遅れて Kubernetes を学び始める - 01. 環境選択編 -
- 一足遅れて Kubernetes を学び始める - 02. Docker For Mac -
- 一足遅れて Kubernetes を学び始める - 03. Raspberry Pi -
- 一足遅れて Kubernetes を学び始める - 04. kubectl -
- 一足遅れて Kubernetes を学び始める - 05. workloads その1 -
- 一足遅れて Kubernetes を学び始める - 06. workloads その2 -
- 一足遅れて Kubernetes を学び始める - 07. workloads その3 -
- 一足遅れて Kubernetes を学び始める - 08. discovery&LB その1 -
前回
一足遅れて Kubernetes を学び始める - 05. workloads その1 -では、Pod,ReplicaSet,Deploymentの3つを学習しました。今回はDaemonSet,StatefulSet(一部)を学びます。
DaemonSet
ReplicaSetとほぼ同じ機能のリソース。
ReplicaSetとの違いは、各ノードに1つずつ配置するのがDaemonSet,バラバラなのがReplicaSet。
用途として、モニタリングツールやログ収集のPodに使う。さっそく、試してみます。
sample-ds.yamlapiVersion: apps/v1 kind: DaemonSet metadata: name: sample-ds spec: selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80pi@raspi001:~/tmp $ k apply -f . --all --prune daemonset.apps/sample-ds created pi@raspi001:~/tmp $ k get all -o=wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/sample-ds-wxzbw 1/1 Running 0 60s 10.244.2.24 raspi003 <none> <none> pod/sample-ds-xjjtp 1/1 Running 0 60s 10.244.1.37 raspi002 <none> <none> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d1h <none> NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR daemonset.apps/sample-ds 2 2 2 2 2 <none> 60s nginx-container nginx:1.12 app=sample-appReplicaSetと大きく違いはありません。
また、各ノードに対してpodが作られていることがわかります。Deploymentと似ているアップデート戦略があり、OnDeleteとRollingUpdate(デフォルト)があります。前者は、podを明示的に削除した(
k delete
)際に更新する戦略です。DaemonSetは、死活監視やログ収集に使うので、手動でのタイミングが効くOnDeleteが好まれます。後者は、Deploymentと同じ動きで、即時更新していく戦略です。ReplicaSetと似ているようで、機能的にはDeploymentに近い感じですね。ReplicaSetはpodが削除されたら複製されますけど、アップデートされません。DaemonSetはpodが削除されたら複製するし、アップデートもされます。試してみます。
sample-ds.yamlapiVersion: apps/v1 kind: DaemonSet metadata: name: sample-ds spec: selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.13 ports: - containerPort: 80nginxのバージョンを1.12から1.13に変更しました。
pi@raspi001:~/tmp $ k apply -f . --all --prune daemonset.apps/sample-ds configured pi@raspi001:~/tmp $ k get all -o=wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/sample-ds-sx4mv 0/1 ContainerCreating 0 5s <none> raspi003 <none> <none> pod/sample-ds-xjjtp 1/1 Running 0 12m 10.244.1.37 raspi002 <none> <none> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d2h <none> NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR daemonset.apps/sample-ds 2 2 1 1 1 <none> 12m nginx-container nginx:1.13 app=sample-appapplyしてみると、一台ずつupdateされています(containerCreating)。Deploymentと違うのは、最大pod数が1のために、一時的にpodが機能しなくなるタイミングが生まれます(超過分の設定不可)。
pi@raspi001:~/tmp $ k delete pod sample-ds-sx4mv pod "sample-ds-sx4mv" deleted pi@raspi001:~/tmp $ k get all -o=wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/sample-ds-hgvtv 0/1 ContainerCreating 0 6s <none> raspi003 <none> <none> pod/sample-ds-k8cfx 1/1 Running 0 4m38s 10.244.1.38 raspi002 <none> <none> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d2h <none> NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR daemonset.apps/sample-ds 2 2 1 2 1 <none> 17m nginx-container nginx:1.13 app=sample-apppodを削除しても、セルフヒーリングで復活します。
StatefulSet
ステートレスなpodではなく、DBのようなステートフルなpod向けのリソース。
podを削除しても、データを永続的に保存する仕組みが存在。
動作自体は、replicaSetと似ている。さっそく、試してみます。
sample-statefulset.yamlapiVersion: apps/v1 kind: StatefulSet metadata: name: sample-statefulset spec: serviceName: sample-statefulset replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80 volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: - ReadWriteOnce resources: requests: storage: 1GmountPathで指定したマウントしたいパスを、volumeClaimTemplatesでマウントしてくれます。 どこに?
![]()
Storageに関しては別で学習することにします。
ひとまず、applyします。pi@raspi001:~/tmp $ k apply -f . --all --prune daemonset.apps/sample-ds unchanged statefulset.apps/sample-statefulset created pi@raspi001:~/tmp $ k get pod NAME READY STATUS RESTARTS AGE sample-ds-hgvtv 1/1 Running 0 54m sample-ds-k8cfx 1/1 Running 0 58m sample-statefulset-0 0/1 Pending 0 5m19s pi@raspi001:~/tmp $ k describe pod sample-statefulset-0 ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 70s (x3 over 2m28s) default-scheduler pod has unbound immediate PersistentVolumeClaims (repeated 2 times)おや、Pendingになってしまいました。
pod has unbound immediate PersistentVolumeClaims
![]()
PersistentVolumeとPersistentVolumeClaims
PersistentVolume(永続的ボリューム)は、名前の通りで、データを永続的に保存しておく場所のリソースです。
マネージドサービスを利用すると、デフォルトでPresistentVolumeが用意されているそうです。
私の環境は、マネージドサービスではなく、自作環境であるので、PresistentVolumeを用意する必要があります。PersistentVolumeClaims(永続的ボリューム要求)は、これも名前の通りで、「PresistentVolumeを使わせて」というリソースです。
このリソースで、PresistentVolumeのnameを指定し、applyすることで、初めてマウントができます。
例えば、PodからPersistentVolumeClaimsの名前を指定してあげると、そのPodはClaimしたPersistentVolumeをマウントすることができます。
volumeClaimTemplatesというのは、「わざわざPersistentVolumeClaimsを定義しなくてもテンプレートに沿って書けばClaimsできるよ」というものです。で、何が問題だったの?
pod has unbound immediate PersistentVolumeClaims
のとおりで、「PersistentVolumeの要求をしたけど、Volume割当できなかったよ」とのことです。PersistentVolume(pv)があるのか確認してみます。
pi@raspi001:~/tmp $ k get pv No resources found.たしかにないです。PersistentVolumeを用意しないといけないのですが、どうしましょう。
解決手段として考えたのは3点です。
- GCPやAWS,Azureのサービスを使う
- LocalVolumeを使う
- NFSを使う
1は、書いておいてなんですが、却下です。理由は、せっかくraspberryPiで構築したのでクラウドサービスを利用したくないからです。
2は、Kubernetes: Local Volumeの検証の参考にして試したのですが、 記事にも書いてあるとおり「Local Volumeは他のPodから共有で利用することができない」ため、statefulsetが
replica:1
でなければ動きません。それはそれで動くので学習になり良いのですが、せっかくならreplicaの制限なしにしたいです(ReadWriteManyにしたい)。3は、もう一台raspberryPiを用意して、それをNFSと見立ててPersistentVolumeにしてみる方法です。
3を進めようと思います。
NFS導入
サーバ設定
NFS用の新たなraspberryPiを用意します。設定手順はこちらを参考にしました。
その後の続きは下記です。NFSのホスト名は
nfspi
とします。~ $ slogin pi@nfspi.local pi@nfspi:~ $ sudo apt-get install nfs-kernel-server pi@nfspi:~ $ sudo vim /etc/exports/home/data/ 192.168.3.0/255.255.255.0(rw,sync,no_subtree_check,fsid=0)意味としては、「指定範囲のIPアドレスからのマウントを許可する」。オプションは、こちらを参照。
host ip iMac 192.168.3.3 raspi001(master) 192.168.3.32 raspi002(worker) 192.168.3.33 raspi003(worker) 192.168.3.34 nfspi(NFS) 192.168.3.35 pi@nfspi:~ $ sudo mkdir -p /home/data pi@nfspi:~ $ sudo chmod 755 /home/data pi@nfspi:~ $ sudo chown pi:pi /home/data pi@nfspi:~ $ sudo /etc/init.d/nfs-kernel-server restart pi@nfspi:~ $ service rpcbind status pi@nfspi:~ $ systemctl status nfs-server.service正しく設定されたか、iMacから確認してみます。
~ $ mkdir share ~ $ sudo mount_nfs -P nfspi.local:/home/data ./share/ ~ $ sudo umount shareOK
クライアント設定
各ノードに対して下記を実行します。
pi@raspi001:~ $ sudo apt-get install nfs-commonnfs-client導入
raspberryPi環境では、真っ白な状態なので、一からPersistentVolumeを用意する必要があります。それにはVolumeとなるStorageの型を用意する必要もあるのですが、Storage Classesを見る限り、NFS用の型は標準で存在しません。そこで、nfs-clientを使ってNFS用のStorageClassを作成します。
pi@raspi001:~ $ git clone https://github.com/kubernetes-incubator/external-storage.git && cd cd external-storage/nfs-client/ pi@raspi001:~/external-storage/nfs-client $ NS=$(kubectl config get-contexts|grep -e "^\*" |awk '{print $5}') pi@raspi001:~/external-storage/nfs-client $ NAMESPACE=${NS:-default} pi@raspi001:~/external-storage/nfs-client $ sed -i'' "s/namespace:.*/namespace: $NAMESPACE/g" ./deploy/rbac.yaml pi@raspi001:~/external-storage/nfs-client $ k apply -f deploy/rbac.yamlrbac.yamlにあるnamespaceを現在動かしている環境のnamespaceに置換して、applyしています。
pi@raspi001:~/external-storage/nfs-client $ k apply -f deploy/deployment-arm.yaml pi@raspi001:~/external-storage/nfs-client $ k apply -f deploy/class.yamldeployment-arm.yamlでは、NFSサーバのIPアドレス(192.168.3.35)とマウントパス(/home/data)を設定しました。
class.yamlが、今回欲していたNFSのstorageClass(managed-nfs-storage)になります。※ raspberryPiのイメージはRaspbianを使っているので、arm用のdeployment-arm.yamlを使います。Wiki
これに随分とハマってしまいました...pi@raspi001:~/external-storage/nfs-client $ k apply -f deploy/test-claim.yaml -f deploy/test-pod.yaml試しにマウント先にファイルが作成できているのかテストしています。確認します。
nfspiに移動
pi@nfspi:~ $ ls /home/dataあれば成功です。あれば、下記で片付けます。
pi@raspi001:~/external-storage/nfs-client $ k delete -f deploy/test-pod.yaml -f deploy/test-claim.yamlstatefulsetをリトライ
以上で、StorageClassを用意できました。よって後は、PersistentVolume作って、PersistentVolumeClaim作って...となる予定でした。
しかし、nfs-clientには、dynamic provisioningという機能が備わっており、PersistentVolumeを作らなくても、PersistentVolumeClaimするだけで良くなります。この件については、storageを学習する際に書きます。raspi001に移動して、sample-statefulset.yamlをもう一度applyします。
(storageClassName: managed-nfs-storageを追加, ReadWriteOnce→ReadWriteManyに変更)sample-statefulset.yamlapiVersion: apps/v1 kind: StatefulSet metadata: name: sample-statefulset spec: serviceName: sample-statefulset replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.12 ports: - containerPort: 80 volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: - ReadWriteMany storageClassName: managed-nfs-storage resources: requests: storage: 1Gipi@raspi001:~/tmp $ k apply -f sample-statefulset.yamlnfapiに移動して、あるか確認。
pi@nfspi:~ $ ls -la /home/data total 20 drwxrwxrwx 5 pi pi 4096 May 5 17:18 . drwxr-xr-x 4 root root 4096 May 4 15:50 .. drwxrwxrwx 2 nobody nogroup 4096 May 5 17:17 default-www-sample-statefulset-0-pvc-5911505b-6f51-11e9-bb47-b827eb8ccd80 drwxrwxrwx 2 nobody nogroup 4096 May 5 17:18 default-www-sample-statefulset-1-pvc-5f2fd68e-6f51-11e9-bb47-b827eb8ccd80 drwxrwxrwx 2 nobody nogroup 4096 May 5 17:18 default-www-sample-statefulset-2-pvc-69bee568-6f51-11e9-bb47-b827eb8ccd80ありました! マウントできています!
お片付け
--prune
でも良いのですが、下記のほうが使いやすかったです。pi@raspi001:~/tmp $ k delete -f sample-ds.yaml -f sample-statefulset.yaml pi@raspi001:~/tmp $ k delete pvc www-sample-statefulset-{0,1,2}※
k get pv
とk get pvc
を試して頂き、今回作ったリソースがありましたら削除お願いします。?おわりに
StatefulSetを使える状態にするまでに記事が大きくなってしまいました。次回に詳しく学んでいこうと思います。笑
あと、nfs-clientを見て思ったのが、kubernetesのパッケージマネージャであるhelmを導入した方が、遥かに便利だと思いつつ、手動設定しました。。。
次回は、こちらです。