Quantcast
Channel: 初心者タグが付けられた新着記事 - Qiita
Viewing all 21069 articles
Browse latest View live

#PowerApps のコントロールはグローバル?

$
0
0

前回の「JPPUG758 #4 Power Apps Q&A補足」の補足です。あるいは、Power Apps におけるコントロールはグローバル変数的な扱いなのか?について、です。

結論、グローバル扱いなんですけどね。

コントロールの名前は一意

コントロール名は、そのアプリの中で一意(=ユニーク)になるよう制御されます。

Screen 内で一意ではありません。
アプリ全体で一意です。

実際に、Screen をまたいで同じコントロール名を設定するとエラーになります。同じコントロール名が利用されないようにガードされます。

コントロールをコピー&ペーストした際に、コントロール名が「[コピー元の名称]_1」みたいに、数値が自動的に付与されます。この動作は、同一コントロール名が発生しないように処理されている、と推測できますね。

コントロールはグローバル

コントロール名がアプリで一意である必要は把握できました。では、その他プロパティはグローバル変数のようにScreenを跨いでも利用可能でしょうか?

はい、利用可能ですね。
上記の動画では「SettingsScreen」に配置した「lblSettingTitle」コントロールの[Text]、および[Color]プロパティを「Screen1」に追加したラベルコントロールから参照しています。

これにより、コントロールはグローバル変数のようにScreenをまたいで利用可能なモノである、と確認できました。

活用法

コントロールがグローバル扱いである、という特性を活かして「アプリ全体の設定値を保持するScreen」を作成しておくテクニックがあります。前述のようにアプリの全Screenで表示する文字列や色などを設定用Screenで作成しておいて、利用される各々のScreenはそのコントロールを参照すればよいのです。

例えば、名称や色の変更が発生した場合、その設定用Screenに置いてあるコントロールのプロパティ等を修正するだけで、参照しているコントロールは全て対応完了になります。修正量、極小化されます。

もちろん、コンポーネントを利用しても良いのですが・・・。
コンポーネント機能は、いまだプレビューなのですよ(;^ω^)

まとめ

  • Power Apps のコントロールはグローバル扱い
    • アプリ全体でコントロール名は一意になる
    • Screen をまたいで参照できる
  • 設定用 Screen などを用意して、アプリ全体設定を保持するテクニックもあるよ!

この件も JPPUG758 の現場で質問もらって、その場で回答したんです。が、実際に Power Apps の画面を操作しながら動作等を説明する時間が確保できなかったんです。そのため、記事として補足した次第。

それでは、皆さま。素晴らしい Power Platform Life を!


ABC049C - 白昼夢を簡単に導く方法が知りたい(Golang)

$
0
0

はじめに

ABC049C - 白昼夢を検索文字列の特性上、文字列をリバースして導く方法で解きました。
解きかたはさておき、検索能力の低さゆえ、Goに以下標準関数が見つけられず手作りとなってしまったので、検索能力向上した際には改良したいと思いメモです。

  • 文字列のリバース
  • 開始〜終了桁数を指定した文字列の抜き出し(例:abcを1文字目から2文字目で抜き出して「b」を求める)

コード

packagemainimport("fmt")funcmain(){varsstringannwer:="YES"divide:=[4]string{"dream","dreamer","erase","eraser"}fmt.Scanf("%s",&s)// リバースfori:=0;i<len(divide);i++{divide[i]=getReverse(divide[i])}reverse:=getReverse(s)// 後ろから一致するものを抜き出すj:=0// 開始位置forj<len(reverse){annwer="NO"fori:=0;i<4;i++{// 比較する文字列を必要な範囲で抜き出すvarstrstringfork:=j;k<j+len(divide[i]);k++{ifk>=len(reverse){continue}str+=string(reverse[k])}// 比較ifstr==divide[i]{// 一致した分開始位置をずらすj+=len(divide[i])annwer="YES"break}}// ここにNOで来た時点でアウトなので終わりifannwer=="NO"{break}}fmt.Println(annwer)}funcgetReverse(sstring)string{rs:=[]rune(s)// 今回マルチバイト文字ではないが想定してrunefori,j:=0,len(s)-1;i<j;i,j=i+1,j-1{rs[i],rs[j]=rs[j],rs[i]}returnstring(rs)}

おわりに

冗長すぎておかしくなりそうでした。
あまりニッチではないライブラリで実現可能でしたら教えていただけると嬉しいです。
追伸:別解としてReplaceで一致したら""と置換してしまい、最後0文字になったらYESという方法は認識しております。

[Pythonで遊ぼう] 文章自動生成をめざす ~.txtを読み込み一文単位にする~

$
0
0

はじめに

文章自動生成をめざす、二回目です。前回は文章の構造を調べる形態素解析というのをやりました。今回は、.txtを読み込んで一文ずつに分けるということをしていきます。

文章を読み込む

事前にメモ帳などで作成したテキストデータを用意しておきます。エンコーディング方法には注意しておきましょう。(例では'utf-8'です。)では、文章を読み込んで表示しましょう。

import re
a = open('test.txt', 'r', encoding = "utf-8") 
original_text = a.read()
print(original_text) #文章を表示

こんな感じになります。
2020-02-11.png

テキストデータを整理する

次にテキストデータを整理します。もととなるテキストの書き方次第で、各自調整が必要となります。コードは私のテキストデータの場合です。(例えば'文章(ぶんしょう)'などフリガナの場合は削除しなければならない。)

first_sentence = '「Pythonの説明。」'
last_sentence = 'Pythonという英単語が意味する爬虫類のニシキヘビがPython言語のマスコットやアイコンとして使われている。'
#テキストデータを整理する。
_, text = original_text.split(first_sentence)
text, _ = text.split(last_sentence)
text = first_sentence + text + last_sentence

text = text.replace('!', '。') #!や?を。に変える。全角半角に気を付ける
text = text.replace('?', '。')
text = text.replace('(', '').replace(')', '') #()を削除する。
text = text.replace('\r', '').replace('\n', '') # テキストデータの改行で表示される\nを削除
text = re.sub('[、「」?]', '', text) 
sentences = text.split('。') #。で文章を一文単位に分割
print('文字数:', len(sentences))
sentences[:10] #10文を表示します

できたのがこれ
2020-02-11 (1).png

今回のコードはこれで以上です。これで一文単位のリストができましたね!これを形態素解析にかけて文章にしていく予定です。

雑談

個人的につまづいたところがいくつかあったので紹介。

  • encoding = 'utf-8'を入れてなくてエラー。
  • テキストデータの特徴がつかめてなくて'!'で一文が区切れない

といったところですかね。割と簡単なのに気づかなかったりして時間がかかりました。あと記事にする例文もどうしようか考えた末、無難なもの(WikipediaのPythonの説明文)となりました。

Vue.js + Docker Compose で ホットリロードしながら開発する環境をつくる

$
0
0

はじめに

個人の開発用に Vue.js の動作環境を Docker に移行してみたら、とても捗ったのでメモがてら投稿します。

手順

前提

  • Vue.js のプロジェクトはできている
  • npm run serveで、 Vue.js が立ち上がるように設定されている

1. Dockerfile を作成

プロジェクトの直下に作成します。

FROM node:lts-alpineWORKDIR /appCOPY package*.json ./RUN npm installCOPY . .EXPOSE 8080CMD ["npm", "run", "serve"]

これで、 Vue.js を動作させる Docker Image を作成することができます。

2. docker-compose.yml を作成

こちらもプロジェクト直下に作成します。

docker-compose.yml
version:"3"services:app:container_name:webbuild:context:.dockerfile:Dockerfileports:-8080:8080volumes:-.:/app

voluesでプロジェクトを Docker コンテナにマウントさせることで、 npm run serveの Hot Road が利くようになります。

起動する

プロジェクト直下で下記コマンドを実行します。

docker-compose up

localhost:8080へアクセスすると、 Vue.js が起動しているのが確認できると思います。

終わりに

Dockerはありがたいですね。
少しでもあなたの為になれば幸いです。

githubのリポジトリ完全攻略

$
0
0

githubのリポジトリとは何?

リポジトリは、プロジェクトのフォルダーのようなものです。 プロジェクトのリポジトリにはプロジェクトのすべてのファイルが含まれ、各ファイルのリビジョン履歴が保存されます。 プロジェクトの作業をリポジトリ内で議論し、管理することもできます。

参考↓
https://help.github.com/ja/github/creating-cloning-and-archiving-repositories/about-repositories

どういうタイトルをつければいいのか?

基本的に英語でタイトルをつけます。 
自分で見返した際に何を作ったか分かるようなものが良いです。

例) git-practice, python-first-game等

descriptionとは?

タイトルの説明です。
オプションですので必須ではないですが、後に見返した時のために書いておいた方が良いでしょう。
こちらは英語,日本語どちらでも大丈夫です。
ちなみに私は日本語で書いてます。

例) 〇〇会社のlp模写, Javascriptで〇〇作ってみた

リポジトリは、作っている作品ごとに新しくリポジトリを作成していくものです。

どのタイミングでリポジトリを変更すれば良いのか?

リポジトリは作っているものや学習している内容が変わったら変更します。
かなり変更するので、多くなっていくものです。

PublicとPrivate

公開するか非公開にするかの選択ですね。
書いている内容が余程重要なものではない限り、基本的に公開して問題ないです。

プッシュしていくと

プッシュしていくと、中のファイルが更新されていきます。
追加される訳ではないのでご注意下さい。

終わりに

githubはgitの知識も必要になってくるので初心者の方にはかなり難易度の高いものだと思います。
私自身も手間取りましたね。
gitについて初心者におすすめの書籍があるので良かったら参考にしてみて下さい↓
https://www.amazon.co.jp/%E3%82%8F%E3%81%8B%E3%81%B0%E3%81%A1%E3%82%83%E3%82%93%E3%81%A8%E5%AD%A6%E3%81%B6-Git%E4%BD%BF%E3%81%84%E6%96%B9%E5%85%A5%E9%96%80%E3%80%88GitHub%E3%80%81Bitbucket%E3%80%81SourceTree%E3%80%89-%E6%B9%8A%E5%B7%9D-%E3%81%82%E3%81%84/dp/4863542178/ref=asc_df_4863542178/?tag=jpgo-22&linkCode=df0&hvadid=295686767484&hvpos=&hvnetw=g&hvrand=16461701231400126736&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009243&hvtargid=pla-526224398321&psc=1&th=1&psc=1

CentOS7にDockerをインストールする

$
0
0

CentOSにDockerをインストールする

事前準備

AzureでCentOSのVMを作成しておく。

作成したマシン情報

  • OS: Linux (centos 7.7.1908)
  • マシン名: centos-sample

手順

クライアントのWindowsからteratermで接続する。

rootユーザに変更

sudo su

実行結果

[aky100200@centos-sample ~]$ sudo su

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for aky100200:
[root@centos-sample aky100200]#

パッケージのインストール

  • yum-utils
  • device-mapper-persistent-data
  • lvm2
yum install -y yum-utils device-mapper-persistent-data lvm2

実行結果

[root@centos-sample aky100200]# yum install -y yum-utils device-mapper-persistent-data lvm2
Loaded plugins: fastestmirror, langpacks
Determining fastest mirrors
base                                                     | 3.1 kB     00:00
extras                                                   | 2.5 kB     00:00
openlogic                                                | 2.9 kB     00:00
updates                                                  | 2.6 kB     00:00
(1/5): openlogic/7/x86_64/primary_db                       |  33 kB   00:00
(2/5): base/7/x86_64/group_gz                              | 165 kB   00:00
(3/5): extras/7/x86_64/primary_db                          | 159 kB   00:00
(4/5): updates/7/x86_64/primary_db                         | 6.7 MB   00:00
(5/5): base/7/x86_64/primary_db                            | 6.0 MB   00:00
Package yum-utils-1.1.31-52.el7.noarch already installed and latest version
Package device-mapper-persistent-data-0.8.5-1.el7.x86_64 already installed and latest version
Package 7:lvm2-2.02.185-2.el7_7.2.x86_64 already installed and latest version
Nothing to do
[root@centos-sample aky100200]#

Dockerリポジトリのインストール

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

実行結果

root@centos-sample aky100200]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
Loaded plugins: fastestmirror, langpacks
adding repo from: https://download.docker.com/linux/centos/docker-ce.repo
grabbing file https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
repo saved to /etc/yum.repos.d/docker-ce.repo
[root@centos-sample aky100200]#

docker-ceのインストール

yum -y install docker-ce docker-ce-cli containerd.io

実行結果

[root@centos-sample aky100200]# yum -y install docker-ce docker-ce-cli containerd.io
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package containerd.io.x86_64 0:1.2.10-3.2.el7 will be installed
--> Processing Dependency: container-selinux >= 2:2.74 for package: containerd.io-1.2.10-3.2.el7.x86_64
---> Package docker-ce.x86_64 3:19.03.5-3.el7 will be installed
--> Processing Dependency: libcgroup for package: 3:docker-ce-19.03.5-3.el7.x86_64
---> Package docker-ce-cli.x86_64 1:19.03.5-3.el7 will be installed
--> Running transaction check
---> Package container-selinux.noarch 2:2.107-3.el7 will be installed
--> Processing Dependency: policycoreutils-python for package: 2:container-selinux-2.107-3.el7.noarch
---> Package libcgroup.x86_64 0:0.41-21.el7 will be installed
--> Running transaction check
---> Package policycoreutils-python.x86_64 0:2.5-33.el7 will be installed
--> Processing Dependency: setools-libs >= 3.3.8-4 for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: libsemanage-python >= 2.5-14 for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: audit-libs-python >= 2.1.3-4 for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: python-IPy for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: libqpol.so.1(VERS_1.4)(64bit) for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: libqpol.so.1(VERS_1.2)(64bit) for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: libapol.so.4(VERS_4.0)(64bit) for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: checkpolicy for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: libqpol.so.1()(64bit) for package: policycoreutils-python-2.5-33.el7.x86_64
--> Processing Dependency: libapol.so.4()(64bit) for package: policycoreutils-python-2.5-33.el7.x86_64
--> Running transaction check
---> Package audit-libs-python.x86_64 0:2.8.5-4.el7 will be installed
---> Package checkpolicy.x86_64 0:2.5-8.el7 will be installed
---> Package libsemanage-python.x86_64 0:2.5-14.el7 will be installed
---> Package python-IPy.noarch 0:0.75-6.el7 will be installed
---> Package setools-libs.x86_64 0:3.3.8-4.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package                  Arch     Version             Repository          Size
================================================================================
Installing:
 containerd.io            x86_64   1.2.10-3.2.el7      docker-ce-stable    23 M
 docker-ce                x86_64   3:19.03.5-3.el7     docker-ce-stable    24 M
 docker-ce-cli            x86_64   1:19.03.5-3.el7     docker-ce-stable    39 M
Installing for dependencies:
 audit-libs-python        x86_64   2.8.5-4.el7         base                76 k
 checkpolicy              x86_64   2.5-8.el7           base               295 k
 container-selinux        noarch   2:2.107-3.el7       extras              39 k
 libcgroup                x86_64   0.41-21.el7         base                66 k
 libsemanage-python       x86_64   2.5-14.el7          base               113 k
 policycoreutils-python   x86_64   2.5-33.el7          base               457 k
 python-IPy               noarch   0.75-6.el7          base                32 k
 setools-libs             x86_64   3.3.8-4.el7         base               620 k

Transaction Summary
================================================================================
Install  3 Packages (+8 Dependent packages)

Total download size: 89 M
Installed size: 368 M
Downloading packages:
(1/11): container-selinux-2.107-3.el7.noarch.rpm           |  39 kB   00:00
(2/11): audit-libs-python-2.8.5-4.el7.x86_64.rpm           |  76 kB   00:00
(3/11): checkpolicy-2.5-8.el7.x86_64.rpm                   | 295 kB   00:00
warning: /var/cache/yum/x86_64/7/docker-ce-stable/packages/docker-ce-19.03.5-3.el7.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 621e9f35: NOKEY
Public key for docker-ce-19.03.5-3.el7.x86_64.rpm is not installed
(4/11): docker-ce-19.03.5-3.el7.x86_64.rpm                 |  24 MB   00:00
(5/11): libcgroup-0.41-21.el7.x86_64.rpm                   |  66 kB   00:00
(6/11): libsemanage-python-2.5-14.el7.x86_64.rpm           | 113 kB   00:00
(7/11): policycoreutils-python-2.5-33.el7.x86_64.rpm       | 457 kB   00:00
(8/11): python-IPy-0.75-6.el7.noarch.rpm                   |  32 kB   00:00
(9/11): setools-libs-3.3.8-4.el7.x86_64.rpm                | 620 kB   00:00
(10/11): docker-ce-cli-19.03.5-3.el7.x86_64.rpm            |  39 MB   00:01
(11/11): containerd.io-1.2.10-3.2.el7.x86_64.rpm           |  23 MB   00:02
--------------------------------------------------------------------------------
Total                                               38 MB/s |  89 MB  00:02
Retrieving key from https://download.docker.com/linux/centos/gpg
Importing GPG key 0x621E9F35:
 Userid     : "Docker Release (CE rpm) <docker@docker.com>"
 Fingerprint: 060a 61c5 1b55 8a7f 742b 77aa c52f eb6b 621e 9f35
 From       : https://download.docker.com/linux/centos/gpg
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : libcgroup-0.41-21.el7.x86_64                                1/11
  Installing : setools-libs-3.3.8-4.el7.x86_64                             2/11
  Installing : 1:docker-ce-cli-19.03.5-3.el7.x86_64                        3/11
  Installing : audit-libs-python-2.8.5-4.el7.x86_64                        4/11
  Installing : python-IPy-0.75-6.el7.noarch                                5/11
  Installing : libsemanage-python-2.5-14.el7.x86_64                        6/11
  Installing : checkpolicy-2.5-8.el7.x86_64                                7/11
  Installing : policycoreutils-python-2.5-33.el7.x86_64                    8/11
  Installing : 2:container-selinux-2.107-3.el7.noarch                      9/11
  Installing : containerd.io-1.2.10-3.2.el7.x86_64                        10/11
  Installing : 3:docker-ce-19.03.5-3.el7.x86_64                           11/11
  Verifying  : checkpolicy-2.5-8.el7.x86_64                                1/11
  Verifying  : policycoreutils-python-2.5-33.el7.x86_64                    2/11
  Verifying  : 3:docker-ce-19.03.5-3.el7.x86_64                            3/11
  Verifying  : libsemanage-python-2.5-14.el7.x86_64                        4/11
  Verifying  : 2:container-selinux-2.107-3.el7.noarch                      5/11
  Verifying  : python-IPy-0.75-6.el7.noarch                                6/11
  Verifying  : audit-libs-python-2.8.5-4.el7.x86_64                        7/11
  Verifying  : containerd.io-1.2.10-3.2.el7.x86_64                         8/11
  Verifying  : 1:docker-ce-cli-19.03.5-3.el7.x86_64                        9/11
  Verifying  : setools-libs-3.3.8-4.el7.x86_64                            10/11
  Verifying  : libcgroup-0.41-21.el7.x86_64                               11/11

Installed:
  containerd.io.x86_64 0:1.2.10-3.2.el7     docker-ce.x86_64 3:19.03.5-3.el7
  docker-ce-cli.x86_64 1:19.03.5-3.el7

Dependency Installed:
  audit-libs-python.x86_64 0:2.8.5-4.el7
  checkpolicy.x86_64 0:2.5-8.el7
  container-selinux.noarch 2:2.107-3.el7
  libcgroup.x86_64 0:0.41-21.el7
  libsemanage-python.x86_64 0:2.5-14.el7
  policycoreutils-python.x86_64 0:2.5-33.el7
  python-IPy.noarch 0:0.75-6.el7
  setools-libs.x86_64 0:3.3.8-4.el7

Complete!
[root@centos-sample aky100200]#

インストールの確認

dockerコマンドのパスを確認する。

パスが確認できればOK。

which docker

実行結果

[root@centos-sample aky100200]# which docker
/bin/docker
[root@centos-sample aky100200]#

dockerdの起動

実行してエラーが出なければOK。

systemctl start docker

実行結果

[root@centos-sample aky100200]# systemctl start docker
[root@centos-sample aky100200]#

自動起動設定

systemctl enable docker

実行結果

root@centos-sample aky100200]# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
[root@centos-sample aky100200]#

これでdockerが使えるようになった。

参考

Rails6 DBにsaveする時にROLLBACKしてしまい原因がわからない時

$
0
0

目的

  • DBにsaveする際にROLLBACKしているときのエラーの表示方法をまとめる

実施方法

  • saveの命令の後ろに!をつけてあげるとエラー文が表示される。

具体的な例

  • @user.saveをただ実行しただけの時

    UserExists?(0.5ms)SELECT1ASoneFROM`users`WHERE`users`.`email` = 
    BINARY 'miriwo.rails@gmail.com' LIMIT 1
    (0.2ms)  ROLLBACK
    => false
    
  • @user.save!を実行した時

    UserExists?(0.5ms)SELECT1ASoneFROM`users`WHERE`users`.`email` = 
    BINARY 'miriwo.rails@gmail.com' LIMIT 1
    (0.2ms)  ROLLBACK
    Traceback (most recent call last):
        1: from (irb):21
    ActiveRecord::RecordInvalid (Validation failed: Password can't be blank)
    
  • 最後にエラー文が一文追加されたことがわかる

dockerでHelloWorldする

$
0
0

dockerでHelloWorldする

環境情報

  • OS: Linux (centos 7.7.1908)
  • docker: 19.03.5

手順

イメージの一覧を確認する

docker images

まだ何もないことを確認

実行結果

[root@centos-sample aky100200]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
[root@centos-sample aky100200]#

Hello-Worldの準備

hello-worldイメージをpullする

docker pull hello-world

実行結果

[root@centos-sample aky100200]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
[root@centos-sample aky100200]#

イメージが取得できているか確認

docker images

hello-worldが追加されている

[root@centos-sample aky100200]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        13 months ago       1.84kB
[root@centos-sample aky100200]#

Hello-World

実行

docker run hello-world

実行結果

[root@centos-sample aky100200]# docker run hello-world

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:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

[root@centos-sample aky100200]#

「Hello from Docker!」が出力されている。

まとめ

次はlinuxイメージを作りたい。

参考


dockerでCentOSのイメージを使ってみる

$
0
0

環境情報

  • OS: Linux (centos 7.7.1908)
  • docker: 19.03.5

手順

centos7のイメージを取得

docker pull centos:7

実行結果

[root@centos-sample aky100200]# docker pull centos:7
7: Pulling from library/centos
ab5ef0e58194: Pull complete
Digest: sha256:4a701376d03f6b39b8c2a8f4a8e499441b0d567f9ab9d58e4991de4472fb813c
Status: Downloaded newer image for centos:7
docker.io/library/centos:7
[root@centos-sample aky100200]#

イメージの確認

docker images

実行結果

[root@centos-sample aky100200]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              7                   5e35e350aded        3 months ago        203MB
hello-world         latest              fce289e99eb9        13 months ago       1.84kB
[root@centos-sample aky100200]#

起動

docker run -it -d --name centos7 centos:7

実行結果

[root@centos-sample aky100200]# docker run -it -d --name centos7 centos:7
fdc5ffc971420c60228330c1b9f7b4030878836e74f5590614774e8d35518694
[root@centos-sample aky100200]#

プロセスの起動を確認

docker ps

実行結果

[root@centos-sample aky100200]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
fdc5ffc97142        centos:7            "/bin/bash"         About a minute ago   Up About a minute                       centos7
[root@centos-sample aky100200]#

コンテナ内コマンドの実行

docker exec -it centos7 /bin/bash

実行結果

[root@centos-sample aky100200]# docker exec -it centos7 /bin/bash
[root@fdc5ffc97142 /]#

まとめ

イメージの作成ができた。

参考

AWS試験対策(②コンピューティングとストレージ)

$
0
0

 はじめに

自分はこの前、EC2でサーバを立ててApache入れてWEBサーバを作る…といったことを、動画を参考にしながらやりました。
やったこと自体はいい経験になったし後悔はないんだけど、それって〇〇使ったほうが良くね?って学んでいくうちに気づいたりしました。
AWSは、EC2使わなくてもアプリケーション実行できたりとか色々できます。ただ、EC2でもできますが。
要するに、EC2たててApacheインストールして〜〜とかを、全てAmazonが担当して、こっちはそれ以降のことをするだけでいい、ってな感じ。時短。
その時短サービスに各名前がついてるから覚えるしかない、って感じ
大体略されてるだけだからそんなに難しくはないけど…なんかこういうまとめみたいなやつほしいよね…笑

 EC2

仮想サーバのこと。Running、stopped、terminatedの3つの状態がある。
terminatedは、そのサーバ解約的なイメージ。
課金はRunningのときのみされる。停止ボタン押したら停止中になり、停止完了しようがしまいが、課金は止まる。

なお、OS上で再起動しても、インスタンスは再起動されない。OSが再起動されるだけ。
要するにインスタンス再起動したい場合は、マネジメントコンソールからしかできない。中に入ってshutdown -r nowとかやってもOS再起動のみ。

 EC2の基盤

大きなホストコンピュータ。要するに物理。この上にいろんな人のAWSアカウントからEC2が作られる。一つのサーバを区切ってみんなで使ってるよってこと。マルチテナンシーって言う。
デフォルトでは、どのホストコンピュータにしようか選ぶことができない。

ホストコンピュータに内蔵されたディスクをインスタンスストアという。
ストレージみたいなものだけど、これはホストコンピュータ依存。
EC2は再起動すると、違うホストコンピュータで起動されるが、インスタンスストアは一緒に移動してくれない。
よって、もともとのインスタンスストアを見ることができなくなってしまう。一緒に移動してくれればいいのに。ホストコンピュータ依存だから仕方ないね。。。
言ってしまえば不便オブ不便。使いみちあるこれ?

 EC2のストレージ

  • インスタンスストア

前述の通り、ホストコンピュータが一緒なら使えるストレージ

  • EBS

ブロックストア、要するにストレージです。
インスタンスからは、ディスクとして扱ってくれる。
これは仮想ネットワークディスクであり、ホストコンピュータには配置されていない。そしてEC2の状態がどうなろうとこいつには関係ない。
つまり、独立してて永続性がある!この子がいればインスタンスストアはいらない子だね…
この子はスナップショットっていう写真をS3ってところに残してます。なぜかってS3には安く大量に保存できるから。詳しくは後述

 ハードウェア占有インスタンスとdedicated hosts

マルチテナンシーと違い、ホストコンピュータを自分一人で使えるパターン。
EC2作成時にテナンシーを選択するが、そこで共有を選ぶとマルチテナンシーに。専用、占有ホストを選ぶとこの2つになる。
この2つは何が違うかというと、ハードウェア占有の方は、ホストコンピュータを選べません。dedicated hostsは選べます。アフィニティって設定を使えば、再起動時のホストコンピュータも選べちゃう!インスタンスストアの存在意義ができたね!

上記2つは課金形態がちがいます。
どちらも、物理的なサーバ独り占めですが、ハードウェア占有はインスタンス当たりの課金が必要ですが、dedicated hostsはホストコンピュータ当たりの課金です。
占有よりもdedicated hostsのほうが融通利いて使いやすそう。占有は占有したい人向きだがだったらホストコンピュータ選べるほうがよくね?占有するってことはいっぱい建てたいんだろうし。ならホスト単位での課金のほうが有利な気がする。もしや中途半端…?

IPアドレス

  • EIP

再起動してもIPが継続される、いわば固定IP。使用時は基本無料。
しかし、利用していないときに課金される。AWS側の、使ってない貴重なIPは開放しやがれってメッセージだと思ってる。
ここでいう使用していない時とは、EIP取得はしたけどインスタンスに紐づけていないときや、紐づいてるけどインスタンスがstopped状態のとき。
また、二つ目のEIPを割り当てた場合は課金される。状態問わず。一人一個までだな。
外部インターネットからの接続を想定している。

  • パブリックIP

ランダムに割り当てられるIPであり、再起動時にIPが変わってしまう。
これを自動で割り当てないことも可能。
インターネットとのやり取りに使用。要するにEIPの無課金版。無課金なので固定IPにできない。。。

  • プライベートIP

インスタンス作成時に必ず割り当てられるIP。作成時に任意のIPにもできる。
再起動しても同じIP。EIPの必須版でありプライベート版みたいな感じ。VPC内で使用される。
最初に付与するプライベートIPを、プライマリプライベートIPという。PPIP。
プライマリプライベートIPを指定しない場合、自動でプライベートIPは割り振られる。
PPIPは、インスタンスを削除しない限り保持され、変更不可。インスタンス停止しても保持される。
ただし、ENIってのを使えば、セカンダリプライベートIPをつけることもできる。
インターネットとのやりとりは直接はしない?

ENI

インスタンスに割り当てられるIPアドレスたちは、ENIに関連付けられる。NIC(LANアダプタ)のようなもの。要するにこれがたくさんあれば、たくさんのセグメントでたくさんのIP持てるよってこと。
いくつもてるかはインスタンスタイプによってかわる。

外部DNSホスト名

パブリックIPをもつインスタンスは、外部DNSからホスト名を割り当てられます。
これの確認方法は二通りあり、
- AWSマネジメントコンソールにて確認
- EC2インスタンスのメタデータをクエリ(要求)して確認
の二通りです。
下のほうでする場合、実行中のインスタンスからHTTP経由で取得できる。

SLA

99.99%の可用性らしい。守れない場合、サービスクレジットと言って割引を受けることができる。なお、当たり前だがAWS起因の場合のみ。

AMI

OSのテンプレ。ハードディスク丸写し。
EC2のテンプレってよりは、EBSのスナップショットらしい。
ただのEBSのコピーではなく、OS起動のためのボリュームが追加されたEBSとのこと。
その後にEBSからインスタンス起動されるんだと。まあでも覚え方としてはOSのテンプレが一番早いかも?
別リージョンで使いたい場合は、S3で別リージョンにスナップショットコピーして復元する。EBSコピーだからS3って覚えたらスムーズかも。

インスタンスタイプ

苦手な暗記の領域。何か言い覚え方はないのか。。。

インスタンスタイプインスタンスファミリー特徴
汎用A1/T3/T2/M5/M5a/M4/T3aその名の通り一般的に使われるやつ。これ選んでおけば間違いない。
コンピューティング最適化C5/C5n/C4コンピューティング集約型ワークロード用
メモリ最適化R5/R5a/R4/X1e/X1/ハイメモリ/z1dメモリ負荷の高いアプリケーション用
高速コンピューティングP3/P2/G3/F1汎用GPUコンピューティングアプリケーション用。コンピューティング最適化よりすごいって認識でいいんかね
ストレージ最適化H1/I3/I3en/D2HDDベースのローカルストレージ。高いディスクスループット実現。

ATMから始まるやつは汎用、Cから始まるのはコンピューティング最適化、RXZはメモリ、PGFは高速コンピューティング、HIDがストレージ。
ATMとCは覚えれそう。それ以外はノリで。無理か。

ちなみにT3/T2はバーストできる。Tは特別のTだな!
バーストとは、CPUリソースが通常低負荷で急に高負荷になった場合、低負荷のときの貯金使っていいよってやつ。
バースト使い切っても高負荷のままでやばくなるパターンを想定して、Unlimitedっていうオプションもある(かっこいい)
たとえるなら、スマホの通信制限かかったら「〇〇円で1G追加しませんか?」みたいなメールくるじゃん。それ。

インスタンス購入オプション

  • オンデマンド
    初期費用なしで使った時間に応じての支払い。スタンダード。

  • リザーブドインスタンス(RI)
    一年もしくは三年の予約をすることで割引を受けれる。アマプラは月額300円だけど、一年で入るなら3000円にするよ!みたいなやつと同じ。使う期間がきまっててその間ずっと起動しっぱなしとかならいいんじゃない。
    ちなみに期間中にインスタンスタイプを変更したくなった場合(メモリがもっと欲しい!とか)、差額を払えば変更可能になった。

  • スポットインスタンス
    AWSが未使用のキャパを需要によって時価で提供。
    要するに、ユーザが「500円までなら払うよ!」って宣言し、AWS側の料金が300円とかなら利用可能。
    逆に、ユーザが「500円までなら払うよ!」って宣言し、AWS側の料金が600円とかなら使用不可に。使用不可期間は障害と同じ扱い。中断される。
    なので、必要なログがインスタンス内にあるとかだと取り出せなくなるので停止前に別ストレージに移しておく必要がある。

  • ハードウェア占有インスタンス

  • Dedicated Hosts
    上記二つは先述済み。どちらもHW占領できるがハードウェア占有はインスタンスごとの課金であり、しかもHW選べない。
    インスタンスごとなので、支払い形態は上記のオンデマンド、リザーブド、スポットから選べる。
    Dedicated HostsはHW自体の課金でどこにしようか選べる。

キーペア

インスタンス作成時に公開鍵と秘密鍵が作られる。作成時に秘密鍵を自分でダウンロードできる。SSHログインしたいとき等、この鍵を実行ディレクトリに置いておけば、認証してくれてログインできる。ただし権限変更しないと無理なパターンもあるのでchmodで変更してください。

とりあえずここまで。

Javaアルゴリズム問題を解いてみた(基礎問題)

$
0
0

だいぶ古い記事ですが、CodeZineの過去の連載で
「脱 超初心者 Javaアルゴリズム問題集」というものをみつけました。
https://codezine.jp/article/corner/58
記事によると、「プログラム経験が3ヶ月もあれば十分解くことができるでしょう。」
という難易度らしいので、今の自分にはちょうどよいと思いました。
4問しか記事が見つけられませんでしたが、基礎を復習する意味で時間も意識して実施しています。

以下、問題文を引用させていただいてます。
正答例は記事で御覧ください。
脱 超初心者 Javaアルゴリズム問題集
https://codezine.jp/article/corner/58

第1回 条件分岐と永久ループ

標準入力された値があればそのまま表示、値がなければエラーメッセージを表示するプログラムを作成してください。なお、「EXIT」が入力されるまで、処理を繰り返し続けるものとします。

所要時間目安  A:30分 B:60分 C:120分(A:(開発歴)2年以上、B:1年程度、C:3ヶ月程度を目安)

コマンドラインに入力を待ち受けるための「>」を表示する。
「EXIT」が入力された時点でプログラムを終了する。それ以外が入力された場合は「未入力です」と表示して、再び入力待ち受け状態にする。

キーワード

if文の使用法を習得する。
while()/for(;;)による永久ループの使用法を習得する。

ポイント

標準入力からの入力を受け取るストリームはSystemクラスのフィールドinよりInputStreamクラスのインスタンスとして取得できる。
永久ループは次のようにすることによって表すことができる。

publicstaticvoidmain(String[]args){question1();}publicstaticvoidquestion1()throwsIOException{System.out.print(">");InputStreamReaderwriteConsole=newInputStreamReader(System.in);BufferedReaderbuffer=newBufferedReader(writeConsole);StringwriteString=buffer.readLine();while(true){if(writeString.equals("")){System.out.println("未入力です");}else{System.out.println(writeString);}System.out.print(">");writeString=buffer.readLine();if(writeString.equals("EXIT")){System.exit(0);}}}

第2回 条件分岐(複合条件)

標準入力された月、日が、今日であるかどうかを判定するプログラムを作成してください。

所要時間目安  A:30分 B:60分 C:120分(A:(開発歴)2年以上、B:1年程度、C:3ヶ月程度を目安)

コマンドラインに「今日は何月何日でしょう?」のメッセージを表示する。
それぞれ、「何月?==> 」「何日? ==> 」を表示して入力を受け取る。
入力された月日が今日であれば「正解!!」、間違っていれば「間違っています」と表示する。

キーワード

if文における複合条件の使用方法を習得する。

ポイント

日付の取得は、Calendarクラスを用いて行う。通常のクラスのようにコンストラクタをnewせずgetInstance()メソッドを呼び出してインスタンスを取得する。
標準入力は、Int型で受け取る。
if文は1度しか使用しない。

publicstaticvoidmain(String[]args){question2();}publicstaticvoidquestion2()throwsIOException{System.out.println("今日は何月何日でしょう?");intrightNowMonth=Calendar.getInstance().get(Calendar.MONTH)+1;intrightNowDate=Calendar.getInstance().get(Calendar.DATE);BufferedReaderbuffer1=newBufferedReader(newInputStreamReader(System.in));System.out.print("何月?==>");intwriteMonth=Integer.parseInt(buffer1.readLine());System.out.print("何日?==>");BufferedReaderbuffer2=newBufferedReader(newInputStreamReader(System.in));intwriteDate=Integer.parseInt(buffer2.readLine());if(rightNowMonth==writeMonth&&rightNowDate==writeDate){System.out.println("正解!!");}else{System.out.println("間違っています");}}

第3回 ループ

標準入力から、n個の年齢を受け取り、その平均年齢を算出するプログラムを作成してください。年齢はコマンドライン引数から取得するものとします。

所要時間目安  A:20分 B:40分 C:90分(A:(開発歴)2年以上、B:1年程度、C:3ヶ月程度を目安)

年齢は、コマンドライン引数から取得する。
コマンドライン引数が指定されていない場合は「引数に年齢を指定してください」のメッセージを表示する。

キーワード

for文を使い、n個のループ処理を理解する。
入力チェックを理解する。

ポイント

コマンドライン引数はmain()メソッドにStringの配列型として引き渡される。

publicstaticvoidmain(String[]args){if(args.length==0){System.out.println("引数に年齢を指定してください");}else{intsumAge=0;for(Stringage:args){sumAge+=Integer.parseInt(age);}intaverageAge=sumAge/args.length;System.out.println("平均年齢は "+averageAge+" 歳です");}}

第4回 多重ループと二次元配列

掛け算九九表を出力するプログラムを作成してください。

所要時間目安  A:30分 B:50分 C:100分(開発歴)2年以上、B:1年程度、C:3ヶ月程度を目安)

二次元配列を作成して、九九データの代入を行い、その後の表示は分けて作成する。
ヘッダー、フッタ及び、列ヘッダー(段の表示)は、省いても構いません。

キーワード

for文を使った多重ループ処理を理解する。
二次元配列への代入、参照を理解する。

ポイント

数字を桁をそろえて出力するにはDecimalFormatクラスを使用する。0詰め2桁で出力するにはnewするときにコンストラクタに"00"を渡す。

publicstaticvoidmain(String[]args){System.out.println("+--------- かけ算九九表 --------+");System.out.println("|     1  2  3  4  5  6  7  8  9 |");System.out.println("|  +----------------------------|");inth=1;for(int[]list:question4()){// List<Integer>を利用する場合は以下// for (List<Integer> list : question4_2()) {System.out.print("| "+h+++"|");for(intvalue:list){if(value<10){System.out.print(" 0"+value);}else{System.out.print(" "+value);}}System.out.print(" |\n");}System.out.println("+--+----------------------------+");}//配列を使用publicstaticint[][]question4(){int[][]list=newint[9][9];for(intouter=0;outer<9;outer++){int[]value=newint[9];for(intinner=0;inner<9;inner++){value[inner]=(outer+1)*(inner+1);}list[outer]=value;}returnlist;}//Listを使用publicstaticList<List<Integer>>question4_2(){List<List<Integer>>list=newArrayList<List<Integer>>();for(intouter=1;outer<=9;outer++){List<Integer>value=newArrayList<Integer>();for(intinner=1;inner<=9;inner++){value.add(outer*inner);}list.add(value);}returnlist;}

すべての問題を1問あたり1時間以内に解答できたので楽しめました。
4問目の2次元配列の問題は、Listと配列両方の実装方法を解答しています。
それぞれの違いは、要素数が固定か否かくらいしか理解してませんでしたが、改めて調べると、データへのアクセス方法が異なるため、処理速度に違いがあるらしいことがわかりました。

要素へのアクセス要素の追加
配列高速低速
List低速高速

Slack APIでチャンネルのメッセージを取り出してみる

$
0
0

Webの初心者です。さらに?Qiita初投稿です。
Slack APIを使ってチャンネル内のメッセージ(会話)を取り出す、というのをやってみたので、そのときの手順を書きます。ほかの初心者の方の参考になれば幸いです。

まずはテスト用のワークスペースを作成。convhist(conversation history)という名前をつけました。
image.png

このワークスペース内にapitestというチャンネルを作成。このチャンネルのメッセージ(会話)をSlack APIで取り出すことを目標とします。

  1. Slack Appの作成(API受付準備)
  2. 使用するAPI

1. Slack Appの作成(API受付準備)

"App"とあるのでWebサーバー上にアプリを作るのかと思ったのですが、アプリというよりはむしろワークスペースに参加できる架空のユーザーを作成する感じです。普通のユーザー(人)がSlack画面から操作するのに対し、AppはAPI経由でアクセスする、というイメージです。

APIを使うには、Appの作成 → トークン取得 → APIに必要なスコープの設定、となります。

Appの作成

Appは以下のWebサイトから作成します。Appの作成手順はいくつかのサイトで詳しく書かれているので割愛します。
https://api.slack.com/
このページで、Your Apps > Create New App で、[Create a Slack App] ダイアログがでてきます。
[Create a Slack App]ダイアログにてAppNameを決めます。
App Name: GetConvHist (なんでもいい)
Develpment Slack Workspace: convhist (上記のワークスペース名)

このAppに対する情報設定画面が表示されます。ここでトークン取得およびスコープ設定が必要になります。最低でも一つのスコープを設定(追加)しないとトークンが得られないようです。

ユーザーのトークンとボットのトークン

Appがワークスペースにアクセスするとき、あるときはボットとして、またあるときは自分(App作成者)の代行として振る舞うことができます。どちらで振る舞うかは、APIを実行するときにつかうトークンによって区別されます。

APIに必要なスコープ

Appには、許される操作の範囲を設定する必要があります。許される操作の範囲は"スコープ"と呼ばれるものでカテゴライズされています。ボットとして振る舞うとき、自分(App作成者)の代行として振る舞うときそれぞれに対し、あらかじめ(APIを実行する前に)スコープが設定されている必要があります。

左側のメニューリスト > OAuth & Permissions を選択。
今回は自分(App作成者)の代行として振る舞うことにして、User Token Scopes にスコープを追加します。チャンネルのメッセージを取得するのが目的なので、conversation list と conversation history(後述します) に必要な以下のスコープを追加します。
channels:history
channels:read
image.png

追加したら、その画面の一番上のほうにあるOAuth Tokens & Redirect URLs で、[Install App to Workspace]ボタンを押します。Appがワークスペースにアクセスする権限を[許可]します。すると、OAuth Access Token が得られます。このトークンはAPIを投げるときに使います。ちなみにスコープ設定変更のたびにAppの再インストールが必要です。再インストールといってもこのページ上の画面の操作で済むようになっており、下の添付画面ではボタンが[Reinstall App]になっています。再インストールしてもトークン文字列自体は変わりません。
image.png

もしAppをボットとして振る舞わせたいのなら、Bot Token Scopesにのほうにスコープを追加し、Bot User OAuth Access Token を取得し、APIを投げるときにはそちらのトークンを使います。

これで、ワークスペースがAppからのAPIを受け付けるようになります。

2. 使用するAPIメソッド

Slackの提供する大量のAPIメソッドから、目的のものを探します。チャンネルの情報を取得したいので、channels.???でしょうか? channels.historyというメソッドがあったので、ここからスタートです。まずはAPIメソッドのドキュメントを見ると、channels.historyはすでに非推奨になっており、conversations.historyを使え、とあります。
conversations.historyのページを見ると、メソッドの仕様や必要なスコープが記載されています。
image.png
ユーザートークンでconverstion.historyを使うには、channels:history, groups:hisotry, im:history, mpim:historyが必要となっています。実際には全部必要なわけではなく、操作対象に対応するもの、例えばpublicのチャンネルにアクセスするにはchannels:historyだけでよいようです。
conversations.historyの引数の説明を見てみると、tokenとchannelの2つがRequiredになっています。
image.png

APIメソッドドキュメントのページにはTesterというタブがあり、ありがたいことにお試し実行できるようになっています。いまはapitestというチャンネルの情報を取りたいので、試しに、tokenには上記のOAuth Access Tokenを入力、channelに#apitestと入力して実行してみました。
image.png
送信文字列とレスポンスが見れるようになっています。・・・channel_not_found。失敗しているようです。
image.png

改めて引数を確認すると、channel には Conversation ID なるものを使うことになっています。Conversation IDが何なのかを正当な?手段で調べてはいませんが、conversations.createやconversations.list のレスポンスにid という値があり、これを指すものと思われます。

conversations.listのページのTesterで実行し、そのレスポンスを見ると、apitestというチャンネルに"CTEE1LMQT"というidが割り当てられています。

"ok": true,
"channels": [
    {
        "id": "CTEE1LMQT",
        "name": "apitest",
        "is_channel": true,

conversations.historyのページに戻りTesterでこのidを使って実行すると、今度は成功です。

実際にメッセージを取れるのか確認です。Slackの普通の操作画面で、チャンネルapitestに「helloあいう」というメッセージを送信。この状態でconversations.historyを実行すると、以下のようなレスポンスになっています。最新のメッセージがレスポンスの先頭になるようです。

"ok": true,
"messages": [
    {
        "client_msg_id": "edc34a1f-6e19-47fe-864d-af762c939934",
        "type": "message",
        "text": "hello\u3042\u3044\u3046",
        "user": "UTRUE3W13",
        "ts": "1581446370.000500",

tsはunixtimeのtimestampのようです。メッセージの初回の送信の時刻が維持され、編集しても変わりません。さきほどの「helloあいう」を編集して「helloあいうえお」にするとeditというノードが作成され、そこにまたtsが現れます。

        "ts": "1581446370.000500", ← これは変わらない
        "edited": {
            "user": "UTRUE3W13",
            "ts": "1581446760.000000" ← 編集時刻
        },

API送信の確認

検索して最初に目についたpython slackclientを使ってみました。slackclientのドキュメントはここです。
メッセージごとにテキストのみを取り出しファイルに書き込むという簡単なコードです。

importslacktoken_str={OAuthAccessToken}client=slack.WebClient(token=token_str)response=client.conversations_history(channel="CTEE1LMQT")forresinresponse["messages"]:print(res['user'])print(res['ts'])if('edited'inres):print('edited_ts='+res['edited']['ts'])withopen(f"./slack/{res['user']}_{res['ts']}","w")asf:f.write(res['text'])

以上、すこしでも参考になれば幸いです。

Rの基本(:, seq(), c(), rep() )--- 初心者向け---

$
0
0
tags: rBasicLearning

Rの基本

Rでよく使われるものについてまとめましたので, 宜しければ, ご覧ください!

データの代入(<-)

ほとんどの言語では, データの代入は "=" で表されるが,
R言語の場合は "<-" で表される.
ショートカットとしては, "option" + "-"

:(COLON OPERATOR)

左の番号を最小値として取り, 右の番号を最大値として取る.
そして, 左の番号以上・右の番号以下で数字を連続的に取る.

# COLON OPERATOR ############################################ Assigns number 0 through 10 to x1x1<-0:10x1# Descending orderx2<-10:0x2
># Assigns number 0 through 10 to x1>x1<-0:10>x1[1]012345678910># Descending order>x2<-10:0>x2[1]109876543210

seq()

seq(x)に入力された値を最大値とし, 1からその値まで, 連続した値を取る.
seq(x, y, by = z)で, x から y までを z の値ごとに取っていくというようにする.

# SEQ ####################################################### Ascending values (duplicates 1:10)(x3<-seq(10))# Specify change in values(x4<-seq(30,0,by=-3))
># SEQ ######################################################># Ascending values (duplicates 1:10)>(x3<-seq(10))[1]12345678910>># Specify change in values>(x4<-seq(30,0,by=-3))[1]302724211815129630

c()

数字の行を鎖状に繋げ, 行ベクトルにする.
"Concatenate" は, 鎖状に繋げるという意味.
c(a, b, …)

# ENTER MULTIPLE VALUES WITH C ############################## c = concatenate (or combine or collect)x5<-c(5,4,1,6,7,2,2,3,2,8)x5
>x5<-c(5,4,1,6,7,2,2,3,2,8)>x5[1]5416722328

rep()

繰り返し, その値を出すことができる.
rep(繰り返したいデータ, 繰り返す回数)
行ベクトルの時は, 一セットごと繰り返す.
各要素ごとに繰り返したいときは, eachで指定する.
rep(繰り返したいデータ, each = x)

# REP ######################################################x7<-rep(TRUE,5)x7# Repeats setx8<-rep(c(TRUE,FALSE),5)x8# Repeats items in setx9<-rep(c(TRUE,FALSE),each=5)x9
># REP ######################################################>>x7<-rep(TRUE,5)>x7[1]TRUETRUETRUETRUETRUE>># Repeats set>x8<-rep(c(TRUE,FALSE),5)>x8[1]TRUEFALSETRUEFALSETRUEFALSETRUEFALSETRUEFALSE>># Repeats items in set>x9<-rep(c(TRUE,FALSE),each=5)>x9[1]TRUETRUETRUETRUETRUEFALSEFALSEFALSEFALSEFALSE

Docker初学者が理解しにくかったことをまとめる

$
0
0

はじめに

社内でDockerの読書会を定期的に行っていました。
初心者が多い読書会にて自分たちが理解しにくかったことを記述します。
ここでは、以下の事項を記述します。

  • コンテナ型仮想化について
  • Dockerのイメージについて
  • コンテナのライフサイクルについて

コンテナ型仮想化について

書籍でのコンテナ型仮想化技術の説明では、ホスト型仮想化技術と一緒に取り上げられることが多いと感じます。
読書会では仮想化技術の簡単なイメージがまったくなければ、説明を呼んでもピンとこない場合がありました。
そこで、仮想化技術、ホスト型仮想化技術について簡単に記述した後、コンテナ仮想化技術について説明します。

仮想化についてのイメージ

仮想化とは1台の物理サーバ(あるいはPC)の中に、あたかも別のサーバを稼働させることを指します。
基本的には1台のPCにOSは1つしかありません。仮想化技術を使うと、1台のPC上に複数のOSを稼働させることができ、またそれらのOS上でもアプリケーションを稼働させることができます。
物理サーバのOSをホストOSと呼ばれ、仮想化技術を用いたOSはゲストOSと呼ばれます。
仮想化技術を用いて作成された環境を仮想環境といい、仮想環境は論理的に区画されており、環境が隔離されているように見えます。
余談ですが、仮想環境との疎通確認や、通信、ネットワークを考える時には、常に仮想環境が隔離されていることを認識しておかないと、ハマることが読書会では多かったです。

ホスト型仮想化技術について

ホスト型サーバ仮想化技術は、ホストOSに仮想化ソフトウェアをインストールし、その仮想化ソフトウェア上でゲストOSを動作させる技術を指します。
仮想化ソフトには「Oracle VM VirtualBox」、「Vmware Workstation Player」などがあります。

構成としては以下の図のようになります。
ホスト型仮想化技術.png

コンテナ型仮想化技術について

まず、コンテナとは何か。「プログラマのためのDocker教科書 第2版」から引用すると、

コンテナとはホストOS上に論理的な区画を作り、アプリケーションを動作させえるのに必要なライブラリやアプリケーションなどを1つにまとめ、あたかも個別のサーバのように使うことができるようにしたもの.

この説明だけではコンテナについて理解できるわけではなかったのですが、「Docker/Kubernetes 実践コンテナ開発入門」では以下のように説明があり、

「コンテナとはDockerによって作成されるゲストOS」

と捉えた上であれば理解しやすいかもしれません。

我々初心者が手っ取り早く理解するために、ホスト型にしろ、コンテナ型にしろ、ホストOSとは隔離された仮想環境を構築する点については同じように捉えてもいいと思います。

初学者にとってのホスト型仮想化とコンテナ型仮想化との大きな違いは、軽量で高速な起動・停止ができるどうかだと思います。
コンテナを使用した仮想化システムは、ホスト型に比べて明らかに環境構築がスムーズで、簡単な操作で実行環境を起動することができます。

コンテナ仮想化の構成を以下の図に示します。
コンテナ型仮想化技術.png

Dockerの操作について

読書会では、Dockerの操作(イメージ作成~コンテナの破棄まで)について序盤で取り扱ったものの、操作に対して理解がしにくいという声をもらいました。
掘り下げていくと、Dockerのイメージ、コンテナのライフサイクルについて理解が浅いことがわかりました。

Dockerの操作を初めて学習する方、あるいは操作について理解が浅い方向けに、イメージ、コンテナのライフサイクルについて理解する必要があると考え、本節ではそれらの事項について説明します。

Dockerイメージについて

まず、引用から。
「プログラマのためのDocker教科書 第2版」では、下記の通りに説明しています。

Dockerはアプリケーションの実行に必要になるプログラム本体/ライブラリ・ミドルウェアや、OSやネットワークの設定などを1つにまとめてDockerイメージを作ります。Dockerイメージは実行環境で動くコンテナのもと(ひな型)になります。Dockerでは1つのイメージには1つのアプリケーションのみを入れておき、複数のコンテナを組み合わせてサービスを構築するという手法が推奨されています。

また、「Docker/Kubernetes 実践コンテナ開発入門」では、DockerイメージとDockerコンテナの役割について端的に説明しています。

Dockerイメージ:Dockerコンテナを構成するファイルシステムや実行するアプリケーションや設定をまとめたもので、コンテナを作成するための利用されるテンプレートとなるもの。
Dockerコンテナ:Dockerイメージをもとに作成され、具現化されたファイルシステムとアプリケーションが実行されている状態。

これらをざっくりまとめてみると、イメージとは、Dockerを使用したアプリケーション(コンテナ)を実行する前に、実行に必要となるリソース(ファイルシステム、ライブライリ等)を集めたテンプレートみたいなもの。
「イメージというテンプレを作ると、それ通りにアプリケーションが実行される」みたいな認識をすると、理解しやすいのではないでしょうか。

コンテナのライフサイクル

コンテナのライフサイクル(状態遷移)は以下の図のようになります。
コンテナのライフサイクル.png

docker runコマンドではコンテナを生成して起動までしています

Dockerイメージを作成すると、コンテナを生成あるいは起動できるようになります。コンテナの生成と起動の大きな違いは、コンテナ上にある何らかのプロセスが実行されるどうかです。

コンテナのライフサイクルを理解すると、コンテナの簡単な操作のイメージがしやすいと思います。

参考文献

Rails6 each を使った時にDBのレコードの内容が全て出力されてしまう

$
0
0

目的

  • eachを用いた時に意図しない出力になってしまったので解決方法を記載する。

症状

  • 下記のコードを用いてDBのとあるテーブルのレコードの内容を出力したところレコードの全ての内容が最後に出力されてしまう。

    <%=@posts.eachdo|post|%><%=post.content%><br><%=post.link%><br><%end%>

    ↓出力

    testでーす
    https://qiita.com/miriwo
    [#<Post id: 1, content: "testでーす", created_at: "2020-02-08 00:54:38", updated_at: "2020-02-08 00:54:38", link: "https://qiita.com/miriwo">]
    

原因

  • 単純なミス
  • @posts.each do |post|の部分を<%= %>で囲んでしまっていたため、処理部分が出力されてしまった。

正しいコード

  • 下記に正しいコードを記載する。

    <%@posts.eachdo|post|%><%=post.content%><br><%=post.link%><br><%end%>

    ↓出力

    testでーす
    https://qiita.com/miriwo
    

教訓

  • <%= %>は結果を出力したい時のみ使用する。
  • <% %>は結果を出力したくない時に使用する。

Lambda関数を設定してS3イベントで動かそう!

$
0
0

Lambdaってなに?

AWSの提供するサービスの一つで、サーバ管理をすることなく処理を実行することができるサービスです。

例えばLambdaを利用しない場合、EC2でサーバを作成し処理実行に必要なミドルウェアや言語をインストールし、環境設定をすることで初めて処理が実行されます。

しかし、Lambdaではそのようなサーバのプロビジョニングをすることなく、処理を書くだけで実行することが可能になります。

これにより、
★サーバ自体の管理・メンテナンスが不要
★処理が実行されている時間のみ課金されるので処理の頻度によってはコストを大幅削減可能
★他AWSサービスと容易に連携できるので、AWSメインのアーキテクチャでは大変便利
というメリットがあります。

トリガーとは?

書いた処理を実行させるにはトリガーというものを設定する必要があります。
AWSのあらゆるサービスと連携ができ、CloudWatchでアラームが出たら実行、kinesis data stream にデータが存在するとき実行、S3にファイルが置かれたら実行などが代表的な例になります。

つまりLambdaは実行する条件実行される処理だけを書けば動いてくれるサービスなのです。

実際に設定したい!

ではs3にファイルをアップロードし、アップロードされたことを確認する処理を書いてみましょう。

1.AWSコンソールにログインし、Lambdaの画面で「関数の作成」をクリック

Lambdaはリージョンごとに関数を設定することになります。
S3の場合は問題ないですが、他リージョンの影響を受けるサービスと連携するときは同じリージョンを選択しましょう。
image.png

2.「1から作成」を選択し、「関数名」と「ランタイム」、「実行ロール」を設定

今回はpython 3.7を利用します。
ロールは「基本的なLambdaアクセス権限で新しいロールを作成」にします。
既存のロールを利用でも問題ないです。
その場合、Lambdaがトリガー条件のサービスやLog出力用のCloudWatchへのロググループ書き込み権限がある必要があります。
※新規作成の場合はCloudWatchのロググループ書き込み権限は自動でアタッチされます。

「ランタイム」とは処理の言語を意味します。2020/02/05時点では選択できる言語は下記となっております。
・Java 11/8
・.NET Core2.1(C#/PowerShell)
・GO 1.x
・Node.js 12.x/10.x
・python 3.8/3.7/3.6/2.7
※カスタムランタイムを利用することであらゆる言語を利用できるようになりますが、本記事では省略します。
image.png

3.「トリガーを追加」で実行条件を設定

今回はs3に何かオブジェクトが作成されたときに実行できるようにします。
トリガー媒体をs3に設定したときの項目は下記の5つになります。
・バケット
・イベントタイプ(ファイルがPUTされたら・・・、ファイルが削除されたら・・・など)
・プレフィックス(バケット以降のディレクトリパスやファイル名など)
・サフィックス(ファイル名や拡張子など)
・トリガーの有効化(チェックするとすぐ上記設定のトリガーが動きます。処理のテストが終わってからonにしましょう)
image.png

4.関数コードを設定

デフォルトではlambda_function.pyというファイルに処理が記述されています。

lambda_function.py
importjsondeflambda_handler(event,context):# TODO implement
return{'statusCode':200,'body':json.dumps('Hello from Lambda!')}

lambda_handlerとはLambdaに設定されているトリガー条件が満たされたときに自動的に実行される関数です。
# TODO implement以降を編集し、実行したい処理を書きましょう。

今回はs3にファイルが置かれたら置かれたパスとファイル名を表示するようにしてみます。

lambda_function.py
importjsondeflambda_handler(event,context):bucket=event['Records'][0]['s3']['bucket']['name']key=event['Records'][0]['s3']['object']['key']print(bucket+'バケットに'+key+'が作成されました!')

lambda_handlerに引数で渡しているeventにはトリガーとなったイベント情報が配列で入っており、
上記はそこからバケット名とファイルパスを取得し、表示を行っています。

5.実行・確認

関数の実行自体はトリガーで指定したパスにファイルを置くことで実行できます。
それ以外にも下画像の「テスト」からeventに入る値をjson形式で設定することにより疑似的にLambda関数を実行することが可能です。
tempsnip.png

また、関数の実行LogについてはCloudWatchのロググループから対象の関数を選択し、そこから確認することが可能です。
tempsnip.png


正しくLambda関数が実行できていることが確認できました!!
tempsnip.png

終わりに

LambdaはAWS環境を利用しており、シンプルな処理をおこなうのであればコスト面、管理面でもとてもおススメです。
少し気になったのは関数が何をしているかの説明文を書いておく欄がないので、わかりやすい関数名・処理内でのコメント記載を徹底し、快適なLambdaライフをおくりましょう!!

新米エンジニアがクラウド(AWS)上での検証環境構築に挑戦してみた

$
0
0

1.はじめに

1.1.背景

先日、「AWS上に検証環境を作って,バーチャルアプライアンス(FortiManager,FortiAnalyzer)の機能検証をしてほしい」とお願いされました.

恥ずかしながら当時の私はバーチャルアプライアンスのことはおろかAWSのことさえほぼ何も知らず、分からない単語だらけのミッションだったのですが,周囲の方々の協力のおかげでどうにか形になってきました。
試行錯誤の過程で、知らないとハマってしまうであろうポイントがいくつか出てきたため、アウトプットも兼ねて皆さんとナレッジを共有させていただきたいと思います.

本記事では機能検証の内容そのものではなく、その前段であるAWS上に検証環境を構築する方法に焦点を絞って解説したいと思います。
機能検証の内容自体については、またいずれ別記事でまとめる予定ですので、興味がある方は是非そちらもご覧ください。

今回はFortinet社のバーチャルアプライアンスを用いていますが、もちろん他ベンダーの様々なアプライアンスにも応用可能な内容だと思いますので、もしも皆さんが同じようなことをする際は、少しでも参考にしていただければ幸いです.

また,「他にもやり方あるよ!」「自分はこんな感じでやってるよ!」という方がいらっしゃれば,是非ともコメントでご教授いただければと思います.

1.2.対象読者

AWS初心者の方で、「興味はあるけど何をしたらいいか分からない」「本やドキュメントなどでAWSについて一通り勉強したけど、実際どんな風に使ってみたらいいか分からない」といった方のイメージをつかむ一助になれればと思います。
私自身もまだまだ初心者のため、「既にAWSをバリバリ使ってるよー」というベテランの方には冗長な表現や不完全な部分もあるかと思いますが、そのあたりはご容赦ください。

ちょいちょい出てくるAWSのサービス名や機能などは出来るだけリンク化して、そのサービスに関するAWSの公式ドキュメントに飛べるようにしてあるので、もっと詳しく知りたい方はそちらも併せてご覧ください。

また現在進行形でアプライアンスの検証などをオンプレで行っているというインフラエンジニアの方は、是非今後の選択肢の一つにしていただければと思います。

2.クラウド(AWS)上に検証環境を構築するメリット・デメリット

新米エンジニアなりに考えて書いたものですが、少し長くなってしまったので別記事にまとめてあります。
インフラエンジニアの方以外にはあまり関係ない内容かもしれませんが、もし興味をお持ちいただけましたら是非ご一読ください。
クラウド(AWS)上に検証環境を構築するメリット・デメリットまとめ

3.検証対象

まず、今回の検証対象アプライアンスである

- FortiManager
- FortiAnalyzer

について簡単にご説明します。
私も今回依頼されるまで全く見識がありませんでした。
これらは、アメリカのセキュリティベンダー大手であるFortinet社が展開している製品群の内の一つです。

FortiGateという、同社の販売しているファイアウォールがあるのですが、FortiManager・FortiAnalyzerは、これを管理・監視するための補助的なアプライアンスという位置づけになります。

それぞれ非常に多岐にわたる便利な機能がある(らしい)のですが、少なくとも今回の検証では、

- FortiGate=ここに来た通信を事前に設定したポリシー(ルール)によって通すか通さないか決めるアプライアンス(一般的なファイアウォールのイメージ)
- FortiManager=複数のFortiGateを一元的に管理するためのアプライアンス
- FortiAnalyzer=各FortiGateに来た通信のログをまとめて解析するためのアプライアンス

といった程度の理解でまず支障ありません。
各アプライアンスの機能に関する詳細な説明については、申し訳ありませんが本題から外れてしまうので今回は割愛させていただきます。
いずれまとめるかもしれませんし、まとめないかもしれません(笑)

今回の検証の目的は、FortiManager・FortiAnalyzerの大雑把な使用感を知ることです。
割とマイナーな製品であるため社内にもノウハウを持つ人が少なく、顧客に提案しようにも実際これがどういうものなのかが分からないため、とりあえず試しに検証してみてほしいとのことでした。
ですがマイナーすぎて社内に検証用の実機すら無かったため、ライセンスだけ取得してAWS上にバーチャルアプライアンスを展開し、それを利用して検証を行ってみよう、といった運びになったのが始まりです。

4.検証環境構築

4.1.論理構成

とりあえずこのような論理構成図を作成してみました。
論理構成図.png

4つのセグメントで構成された、非常にシンプルなLANです。
192.168.1.0/24が管理セグメントになります。
各インターフェースに振るIPアドレスは基本的に何でもいいのですが(0,1,2,3,255の5つはAWS側で予約されているため使えません)、本記事では分かりやすくするため第4オクテットはアルファベットで表記してあります。

送信元の検証用サーバーEC2_01からの通信がFortiGate_01とFortiGate_02を経由して、宛先の検証用サーバーEC2_02に到達するような経路を想定しています。
論理構成図_01_想定経路.png

最初の目標は、とりあえずこの経路で無事にPingの疎通が取れることを確認することです。
無事に検証環境が構築できたら、この構成を使って以下の2つの検証を行っていきます。

4.1.1.各FortiGateのポリシーがFortiManagerで一元管理できるか

論理構成図_検証1.png

4.1.2.FortiGateを通過した通信についてのログをFortiAnalyzerに転送し、解析できるか

論理構成図_検証2.png

4.2.AWSコンポーネント

それではまず先ほどの論理構成図を一つずつAWSのコンポーネントで構築していきます。
AWS初心者の方でもなるべく理解しやすいよう丁寧に説明していく予定ですが、流石にAWSの各サービスやインスタンスの具体的な作成手順に関してまでは、そこまで詳細な説明を行えません(とんでもない分量になってしまいます)。
なので詳しくは公式ドキュメントを参照したり、実際にAWSコンソールで手を動かしてみてください。
また、今回はあくまで検証環境ということで、リージョンやAZ(アベイラビリティーゾーン)にも特にこだわりませんのでご了承ください。

4.2.1.VPC

まずはVPC(Virtual Private Cloud)を用意します。
構築するネットワークの入れ物ですね。
今回は192.168.0.0/16というIPv4 CIDRブロックを割り当てました。
AWS構築過程_01_VPC.png
まだ、ただの箱です。

4.2.2.サブネット

続いて、この中にサブネットを作成します。
先ほどの論理構成図にあったセグメントの

  • 192.168.1.0/24
  • 192.168.2.0/24
  • 192.168.3.0/24
  • 192.168.4.0/24

をPrivate_subnetで、またインターネット接続用にPublic_subnetとして192.168.5.0/24を作成します。ついでに、VPCにはインターネットへの出入り口であるInternet Gatewayを取り付けます。
AWS構築過程_02_サブネット.png

4.2.3.EC2の作成

いよいよサブネット内に配置するEC2インスタンスの作成に入ります。

4.2.3.1.踏み台サーバー、検証用サーバー

今回は踏み台サーバー(Windows_01)、検証用サーバー(Windows_02,Windows_03)ともに、OSにWindows Server 2019を使用します。
検証用サーバーのOSはLinuxでももちろん構いません。
検証用にWindowsサーバーを使用する場合は、OSのファイアウォールを解除しておくことを忘れないでください(ここでパケットが弾かれると結構気が付きにくいです)。
ここで同時にENI(Elastic Network Interface)の設定も行うため、インスタンスが所属するVPCやサブネット、IPアドレスを指定しましょう。
踏み台サーバーは外部からも接続するので、Private_IPだけでなくPublic_IPも必要です。
ちなみにPublic_IPの取得方法は

  • 無料だがインスタンスが起動するたびにランダムに変わるもの
  • EIP(Elastic IP)を利用するもの

の2種類があります。今回は前者を利用します。

インスタンスの作成途中でセキュリティグループの設定も要求されると思います。
これはざっくり言うと各インスタンスが持つ仮想のファイアウォールのことなのですが、ここはかなり大事なのできちんとドキュメントを読んで勉強することをお勧めします。
セキュリティに関する部分だけあって、取り扱いをミスると色々と実害を被りかねないので。
少なくとも踏み台サーバーはRDPやSSHなど必要最低限のサービスだけを有効にして、接続元も社内ネットワーク限定などにしておくのをお勧めします(使用ポートの変更もしておければなおいいです)。
他にも使用する予定のプロトコルやサービスがあるなら、ここで事前に許可設定を入れておかないと、何もできないインスタンスになってしまうので注意してください。
「なぜかインスタンスにアクセスできないなー」って時は大体ここのせいな気がします。
AWS構築過程_03_EC2_01.png

4.2.3.2.NATインスタンス

Private_subnetから外部のインターネットに接続するためには、NATゲートウェイもしくはNATインスタンスが必要です。
NATゲートウェイは高機能で楽ですが少々コストが高いので、今回はNATインスタンスを使います。
Private_subnet内のインスタンスがインターネットに出る際は、まずこのNATインスタンスにルーティングされ、NATインスタンスが持つPublic_IPに変換されてから外部に接続します。
AWS構築過程_04_EC2_02.png

4.2.3.3.バーチャルアプライアンス

それでは今回のメインインスタンスである、バーチャルアプライアンスを作成していきます。
AWSでは、AWSMarketPlaceというオンラインストアで様々なベンダーのバーチャルアプライアンスが展開されています。
Fortinet社のバーチャルアプライアンスも一通り揃っていますので、ここから必要なものを探しましょう。

アプライアンスの利用形態には、

  • ソフトウェア料金が込み
  • BYOL(Bring Your Own License)

の2種類が存在します。
前者は通常のEC2の使用料金にソフトウェアの使用料が上乗せされているもので、通常のEC2のように従量課金で使えます。
それに対して後者のBYOLというのは、ソフトウェアのライセンスを自前で用意しておけば、後はEC2の使用料のみで使うことができるというものです。
当然ライセンスさえ用意出来るなら後者の方が遥かに安くすみます。
今回は既にライセンスは準備済みなので後者の方法で作成していきます。
基本的な作成手順は通常のEC2と何ら変わりません。
ちなみにBYOLで作成する場合、ライセンスはこの段階で要求されることはありません。

途中で一つ管理用にENIを作らされますが、論理構成図から分かるように今回FortiGateではそれぞれ3つのENIが必要になるので、2個ずつ追加で増やします。
各ENIの所属するサブネットを間違えないようにしてください。

また、ここで非常に重要なのが送信元/送信先の変更チェックという機能を無効にしておくことです!
というのも、AWSインスタンスののENIは、デフォルトで自分のIPアドレス宛のパケット以外を全て自動的に破棄してしまいます。そのため、今回のFortiGateのように複数のENIを持つインスタンスを作ってパケットの中継地点として利用しようとしても、この機能を無効化しない限り全くルーティングされません。
AWSコンソールにて、インスタンスを右クリック→ネットワーキングで設定できます。
私はこれになかなか気づけず、だいぶ時間を浪費してしまいましたので、皆さんはご注意ください。

セキュリティグループはアプライアンス側がデフォルトのものを用意してくれていますので、基本的にはそれで問題ないと思います。
もちろん何か変更を加えるのもありです。

以上でひとまずAWSの構成が完成しました(見た目上は)。

AWS構成図

AWS構成図.png

4.3.バーチャルアプライアンス

続いて、バーチャルアプライアンス内部の設定を進めていきます。

4.3.1.ライセンス認証(BYOLのみ)

今回はBYOLなので、まずはバーチャルアプライアンスのライセンス認証をする必要があります。
まずはRDPで踏み台サーバーにログインし、ブラウザとターミナルソフトをインストールしておきましょう。
Windowsサーバーだと、サーバーマネージャーからソフトウェアをインストールできるように設定しておく必要があるかもしれません。
私はGoogle Chromeとteratermを入れていますが、別に他のものでも十分代用可能です。
ブラウザを開いたら、先ほど設定したFortiGateの管理用IPアドレスにアクセスします。
設定が全て上手くいっていれば、FortiGateのGUI管理画面にアクセスできます。
途中で危ないとかなんとか言われても全て無視してください。
最初は

  • 初期ユーザー名:admin
  • 初期パスワード:自身のインスタンスID

でログインするよう指示されます。
一度ログインしたらパスワードはすぐに変更させられますので、適当なものを考えておいてください(8文字以下だと怒られます)。
ログインに成功するとここでようやくライセンスを要求されるので、あらかじめ用意しておいたライセンスをアップロードします。
ちなみに私が試したところ、一回目はなぜか弾かれるのですが、二回目はすんなり通りましたので、一度失敗したからと言ってすぐに諦めないでください。
ライセンスのアップロードに成功すると、ようやくFortiGateが使用可能な状態になります。
FortiManager,FortiAnalyzerもここまでは全く同じなので同様に進めておきましょう。
全て使えるようになったら、各アプライアンスのGUI画面をブックマークしておくとあとあと楽です。
ブラウザのタブで色々なアプライアンスを同時に管理出来るのは便利ですよ。

4.3.2.インターフェース作成と関連付け

次はFortiGateのインターフェースを作成し、AWSのENIと関連付けしていきます。
まずはFortiGateのGUIからNetwork>Interfaceに移動し、新規インターフェースを3つ作成しましょう。
名前は何でもいいですが、今回はPort 番号にしたいと思います。
タイプはもちろん物理インターフェースです(バーチャルアプライアンスですが)。

アドレッシングモード(インターフェースに割り当てるIPアドレスを決める方法)の設定では、DHCPを選択してください。
この設定にすると、自動的にFortiGate内部のインターフェースとAWSのENIが関連付けされます。
ちなみにマニュアルを選択して手動でIPアドレスを入力すると失敗します。
私はこれをやってしまい、結構ドはまりしました。
設定した見た目はどちらも同じなのですが、マニュアルだとインターフェースがENIと関連付けされないため、使えません。

管理者アクセスは、各インターフェースにアクセスできるサービスを設定できます。
最低でも管理インターフェースであるPort1にはSSH、HTTPS、FMGアクセスを、Ping用のポートであるPort2、Port3にはPINGを許可しておきましょう。
ちなみにFMGアクセスというのは、FortiManagerに管理してもらう時に必要となります。

インターフェースがこのように設定できたら成功です。

FortiGate_01

NameTypeIP Adress/Mask管理者アクセス
Port1物理インターフェース192.168.1.ASSH,HTTPS,FMGアクセス
Port2物理インターフェース192.168.2.EPING
Port3物理インターフェース192.168.3.GPING

FortiGate_02

NameTypeIP Adress/Mask管理者アクセス
Port1物理インターフェース192.168.1.BSSH,HTTPS,FMGアクセス
Port2物理インターフェース192.168.2.FPING
Port3物理インターフェース192.168.3.HPING

4.3.3.スタティックルート作成

インターフェースを作成したら、Network>Static Routeから対向のFortiGateに向けてスタティックルートを設定します。
有効化するのを忘れないようにしてください。

FortiGate_01

DestinationGateway IPInterface
192.168.4.0192.168.2.FPort2

FortiGate_02

DestinationGateway IPInterface
192.168.3.0192.168.2.EPort2

4.3.4.ポリシー作成

いよいよFortiGateのメイン機能です。
Policy&Object>IPv4 Policyから設定します。
ACL(Access Control List)とほとんど仕組みは同じで、基本的には全てImplicit Deny(暗黙の拒否)となっており、許可したい通信の設定のみを一つ一つ登録していくような感じです。
最終的にはこのポリシーをFortiManagerから一括で制御するのが目標ですが、とりあえず最初は疎通確認のために各FortiGateに適当なポリシーをあらかじめ入れておきます。
FortiGateのポリシーは様々な項目を設定できるのですが、とりあえず今はPingが通りさえすればいいので以下のように設定しました。

FortiGate_01

Name着信インターフェース発信インターフェース送信元宛先サービスアクション
3_to_2Port3Port2allallAll ICMPACCEPT
2_to_3Port2Port3allallAll ICMPACCEPT
Implicit DenyAllAllallallAllDENY

FortiGate_02

Name着信インターフェース発信インターフェース送信元宛先サービスアクション
3_to_2Port3Port2allallAll ICMPACCEPT
2_to_3Port2Port3allallAll ICMPACCEPT
Implicit DenyAllAllallallAllDENY

これでFortiGateの設定は全て完了です。
ですが、実はここまでしてもまだ想定した経路の通信は実現できません。
正確に言えば、この状態でWindows_02からWindows_03に向けてPingを打つと疎通自体は確認できてしまうのですが、実はそれは以下の想定経路ではなく、実際の経路の図に示すように、せっかく色々と頑張って設定したFortiGateを完全に無視したものとなっています。

想定経路

AWS構成図_02_想定経路.png

実際の経路

AWS構成図_03_実際の経路.png

4.4.ルートテーブル

なぜこのような挙動になってしまうかといいますと、全てAWSのルートテーブルが原因です。
詳しくはAWSの公式ドキュメントをご参照いただければと思いますが、簡単に言えば、ルートテーブルとはVPC内に存在する暗黙的なルーターのことです。
VPC内の通信は、全てこのルートテーブルによって定義されます。
先ほどの構成において、現在使用しているルートテーブルは以下のようになっています。

Main Route Table(4つのPrivate_subnet全てに関連付け)

DestinationTarget
192.168.0.0/16local
0.0.0.0/0NATインスタンス

Public Route Table(Public_subnetに関連付け)

DestinationTarget
192.168.0.0/16local
0.0.0.0/0Internet Gateway

このlocalの意味ですが、これはこのVPC内の通信(192.168.0.0/16に属する通信)は、全て自動的に直接宛先のENI(NIC)にルーティングされるということを示しています。
これはデフォルトで入っているもので、編集も削除もできません。

また、それ以外の通信(0.0.0.0/0)は全て外部インターネットにルーティングするように追加で設定しています。

このルートテーブルのおかげで、私たちは各インスタンスの細かいルーティング設定を全く意識することなく、簡単に通信を行えるようになっています。
とても効率的で大変ありがたいのですが、しかし今回のアプライアンス検証という目的を考えるとそれでは困ります。
実はこのVPC内のサブネット間の通信をもっと自由に制御する方法を探すというのが、今回の検証環境構築の一番の肝でした。

4.4.1.NG集

正解に入る前に、試行錯誤から生まれた失敗例を少しご紹介しておきたいと思います。
皆さんは同じ失敗をしないでください。

4.4.1.1.VPCのルートテーブルで制御する→失敗

まず最初に私が試した方法は、単純にこのルートテーブルに更に詳細なルートを追加して各サブネットにアタッチしてみるというものでした。
通常のネットワーク機器なら、ロンゲストマッチでこのルートを使ってくれるはずですよね。

Main Route Table(ルート追加の例)
DestinationTarget
192.168.0.0/16local
192.168.4.0/24192.168.3.G
0.0.0.0/0NATインスタンス

しかし結論から言うとこの方法は失敗でした。
どうやらルートテーブルのルールとして、192.168.0.0/16→localよりも詳細な指定をするルートを追加することは出来ないようです。
正確に言うと、そのようなルートを追加したルートテーブルを作成すること自体は可能なのですが、それをサブネットにアタッチしようとするとエラーで弾かれてしまいます。

4.4.1.2.VPCピアリングを利用してみる→失敗

AWSには異なるVPC同士を繋ぐことのできる、VPCピアリングというサービスが存在します。
「同一VPC内では細かいルーティング制御ができないというなら、VPCごと分けてしまえばいいじゃない」といった発想でこれも試してみることにしました。
このサービスを利用するにあたり、少し構成も変更しました。
が、これも失敗です。

VPCピアリングを利用した構成

AWS構成図_04_VPCピアリング.png

VPCピアリングでつながる関係というのは、異なるルートで行ったり来たりは出来ないようです。

4.4.1.3.Transit Gatewayを利用してみる→?

この方法に関しては、もしかすると上手くいくのかもしれません。
が、この方法を試す前に正解を見つけてしまったというのと、このサービスを利用するのには少々コストがかかりそうだというので、実は今回はあまり深く検証していません。
AWSの方に問い合わせたところ、「Ingress Routingという機能を利用すれば可能だと思われる」いった回答は頂いています。
もし興味をお持ちになられた方、もしくは既に試したことがあるという方がいらっしゃいましたら、是非情報提供よろしくお願いします。

Transit Gatewayというのは、最近東京リージョンでも利用可能になったばかりの新しいサービスです。
従来VPC間を繋ぐためには先ほど紹介したVPCピアリングが一般的でしたが、これは推移的なピア関係をサポートしていませんでした。
例えるなら、友達の友達は友達ではないといった感じですかね。
なので複数のVPC同士を接続するためには、どうしてもフルメッシュ構造をとるしかありませんでした。
そこで登場したのが、ハブ&スポーク構造を実現できるTransit Gatewayです。
これを介することにより、複数のVPC間をシンプルに行き来できるようになりました。

先ほどのVPCピアリングではダメだったので、これを使えば上手くいくのではないかと一応構成だけは考えてみました。

Transit Gatewayを利用した構成

AWS構成図_05_TransitGateway.png

Pingを打つためのサーバーを一つ置くためだけにVPCを一つ作るという何とも大げさな構成です。
ですがこれを試す前に正解の方法が見つかりました。
この方法でも上手くいくのか気になる方は是非ご自身で試してみてください。

4.4.2.OSのレイヤーでルーティングする→成功

どうやら各サーバーのOSのレイヤーでルーティングテーブルを書き換えてしまえば、ルートテーブルよりそちらが優先されるようです。
今回はWindows Serverを使用しているので、各Ping要員サーバーに入ってコマンドプロンプトからOSの持つルーティングテーブルを確認し、ネクストホップを追加しました。
ちなみに-pを付けないと再起動するたびにルーティングテーブルがリセットされてしまいます。
追加したらroute printでちゃんと入っているか確認してみてください。

Windows_02(192.168.3.I)にルートを追加

route add 192.268.4.0 mask 255.255.255.0 192.168.3.G -p

Windows_03(192.168.4.J)にルートを追加

route add 192.268.3.0 mask 255.255.255.0 192.168.4.H -p

ついに、無事に想定通りの経路でパケットがルーティングされるようになりました。
Tracertコマンドで確認しても、ちゃんと機能していることが確認できます。
これにて検証環境の構築は完了です。
お疲れ様でした。

5.チェック項目

それでは今までの経緯を踏まえて、AWS上に検証環境を構築する際に気を付けなければいけないことについてまとめておきたいと思います。
疎通確認が取れない時は参考にしてください。

  • VPC
    • サブネットは適切に設定されているか
    • ルートテーブルは適切に設定されているか
  • EC2
    • パブリックIPアドレスは認識しているものと一致しているか(気が付かないうちに変わっている可能性あり)
    • OSのファイアウォールは解除されているか(Windows Serverの時のみ)
    • セキュリティグループは適切に設定されているか(これが一番ありがち)
    • OSのルーティングテーブルは適切に設定されているか
    • 送信元/送信先の変更チェックは適切に設定されているか
  • FortiGate
    • インターフェースはDHCPで設定されているか(マニュアルは×)
    • 管理者アクセスは適切に設定されているか
    • スタティックルートは適切に設定されているか
    • ポリシーは適切に設定されているか
  • その他
    • AWSだけでなく、外部のネットワーク環境に問題はないか(あまり詳しくは言えないのですが、私はこの部分でも苦労しました)
    • コストはちゃんと管理できているか

6.おわりに

いかがでしたでしょうか。
この環境を用いて行った機能検証の具体的な内容についても近いうちまとめる予定ですので、もしご興味をお持ちいただけましたら是非そちらもご覧ください。

今回はAWS初体験ということもあり非常に基本的なサービスに終始してしまいましたが、AWSにはまだまだ興味深いサービスや触ってみたい機能が数えきれないほどありますので、これからも色々と試して皆さんとナレッジを共有していければと思います。
また、もしこの記事を読んで少しでも興味をお持ちになった方がいらっしゃいましたら、是非ご自身でも試していただきたいと思います。

最後まで読んでいただき、ありがとうございました。
それでは、また。

【R】 意外と知らなかったif false

$
0
0

if falseの実装(真偽式のある場合)

条件式をif構文に直接記述する場合、!=のように否定演算子!を使えばいいのは有名だが、

>if(1!=2){print("FALSE")}[1]"FALSE"

こういう書き方もできる。

>if(!(1==2)){print("FALSE")}[1]"FALSE"

さらに、この書き方でもやってることは一緒である。

>if((1==2)==FALSE){print("FALSE")}[1]"FALSE"

if falseの実装(logical型データの場合)

論理型データに直接否定演算子!を付することでスマートに記述できる。

>logi<-FALSE>if(!logi){print("FALSE")}[1]"FALSE"

より直感的な記述法を使うこともできる。

>logi<-FALSE>if(logi==FALSE){print("FALSE")}[1]"FALSE"

さらに、真偽式の場合も同様に!=を使うことができる。

>logi<-FALSE>if(logi!=TRUE){print("FALSE")}[1]"FALSE"

すっきり書きたい JavaScriptの条件分岐

$
0
0

はじめに

未経験からNode.jsの現場に配属された2019年新卒エンジニアが、学習の振り返りとしてJavaScriptの基礎の基礎をまとめます。

過去のJavaScript基礎シリーズ↓
JavaScriptでvarが推奨されない理由を整理してみた

今回は、多くの書き方が存在するJavaScriptの条件分岐に関して、よりすっきりとした書き方を考えていきます。

Goal

  • 思考停止のelseやswitchから離れる
  • 可読性やリファクタリングのしやすさの観点から、JavaScriptの条件分岐を使いこなす

まず「すっきり」を定義する

本記事で目指したい「すっきり」を、以下のように定義します。

  • コードの可読性が高いこと
  • バグが生まれにくいこと
  • 後からリファクタリングがしやすいこと

コードの可読性が高いこと

プロジェクトとして複数人で開発をする際に、可読性の高いコードを書くことはとても重要です。

「可読性」という言葉の意味するところは本記事では割愛しますが、こちらの記事がわかりやすくとても参考になるので、詳しく掘り下げたい方は併せてお読みください。

可読性については、一人で自習ばかりしているとおろそかになってしまいがちな考え方なので、常に考えておく癖をつけておきたいですね。

バグが生まれにくいこと

これは、書き忘れや書き間違いによるバグが発生しにくい、といった意味合いです。期待していない動作の場合に、エラーとして表示される等でバグに気づきやすい書き方は、未然にバグを防げます。

後からリファクタリングがしやすいこと

後から仕様の追加や変更があった際に、対応しやすいコーディングを指します。

ピンとこない方はこちらの記事が、リファクタリングの重要性を分かりやすくまとめていただいていますので、ぜひお読みください。

JavaScriptの条件分岐をおさらい

ということで、「可読性が高く」「バグが生まれにくく」「後からリファクタリングがしやすい」条件分岐の書き方を考えていきたいと思うのですが、その前にまず、JavaScriptの条件分岐に用いられる基本的な構文を整理します。

基本的な書き方

  • else文
  • if...else文
  • switch文

やや応用的な書き方

  • 三項演算子
  • 短絡演算子

基本的な書き方

else文

constpokemon={name:"ヤドン"};constisGalar=pokemon=>{if(pokemon.name==="ヤドン"){returntrue;}else{returnfalse;}};console.log(isGalar(pokemon));// ログの出力結果は"true"

多くのプログラミング教材で最初に習う条件分岐が、おそらくこの構文ではないかと思われます。if文で条件に合致した場合の式が実行され、合致しなかった場合はelseが実行されます。

ただし、条件に合致しない場合はif文以下の実行が無視されるだけなので、上の例のような単純な真偽判定のみであれば、以下のようにelseを省略することが可能です。

constisGalar=pokemon=>{if(pokemon.name==="ヤドン"){returntrue;}returnfalse;};

else if...文

constyadon={name:"ヤドン"};constgalarPokemon={name:"ヌオー",galarNumber:101};constkantoPokemon={name:"ヒトデマン"};constisGalar=pokemon=>{if(pokemon.galarNumber){returntrue;}elseif(pokemon.name==="ヤドン"){returntrue;}else{returnfalse;}};console.log(isGalar(yadon));// 出力結果は"true"console.log(isGalar(galarPokemon));// 出力結果は"true"console.log(isGalar(kantoPokemon));// 出力結果は"false"

こちらも、初歩的な条件分岐としてよく出てきますね。3つ以上の条件分岐が必要な場合に活用する構文です。

ただ、JavaScriptに「else if」構文というものはありません。実際の挙動としてはelse文の中でさらにif節とelse節のネストが生成されているのと等しいようです。
また、この書き方でもelseの省略が可能です。以下のコードは上記の例と同様の実行結果となります。

constisGalar=pokemon=>{if(pokemon.galarNumber){returntrue;}if(pokemon.name==="ヤドン"){returntrue;}returnfalse;};

switch文

constevolutionEevee=stone=>{leteevee;switch(stone){case"ほのおのいし":eeVee="ブースター";break;case"みずのいし":eevee="シャワーズ";break;case"かみなりのいし":eeVee="サンダース";break;default:eevee="イーブイ";}returneevee;};console.log(evolutionEevee("ほのおのいし"));// 出力結果は"ブースター"console.log(evolutionEevee("みずのいし"));// 出力結果は"シャワーズ"console.log(evolutionEevee("かみなりのいし"));// 出力結果は"サンダース"console.log(evolutionEevee("かたいいし"));// 出力結果は"イーブイ"

こちらも、複数の分岐が発生する条件式における定番の書き方です。case ○○:で条件を分岐させ、いずれのcaseにも一致しなかった場合はdefaultの式が実行されます。

注意すべき点は、case節やdefault節で条件分岐の処理を書いた後のbreakの有無によって、switchの実行が異なるという点です。

switch文は、処理の中でbreakが入力されていた場合に条件の判定をやめ、switch文を抜けて次の文から実行を続けます。

breakが入力されていないと条件に合致したcase節があってもswitch文が継続されてしまうのです。

breakが無い場合の挙動は以下のようになります。

constevolutionKlink=pokemon=>{letgrade;switch(true){case/ギギギアル/.test(pokemon):grade=3;case/ギギアル/.test(pokemon):grade=2;case/ギアル/.test(pokemon):grade=1;}returngrade;};console.log(evolutionKlink("ギギギアル"));console.log(evolutionKlink("ギギアル"));console.log(evolutionKlink("ギアル"));// いずれも出力結果は「1」

上の例では、test関数を利用して、引数pokemonを正規表現によって判定する関数を実行しているのですが、breakを書かなかったせいで、手前のcaseに合致する場合でも全てのcaseで判定が行われ、意図しない結果が出力されてしまっています。breakを書けばこのバグは防ぐことができます。

あえてbreakしないswitchの書き方というのもあるようですが、基本的にswitchを使うならbreakを忘れずに書いた方が安心ではないかと思います。

もしくは、case節で直接return文を書き、条件に一致したcase以降の式を読み取らせないようにするのが良いでしょう。

やや応用的な書き方

三項演算子

ifを用いない条件分岐の書き方として、三項演算子というものがあります。
これは、if文でブロックを分けたくない場合に、コンパクトに条件分岐を書くことができるとても便利な構文です。構文は以下の通りです。

条件式 ? 条件がtrueの場合の処理 : 条件がfalseの場合の処理

たとえば以下のように、変数に代入する値を条件分岐で決めたい時に使われることが多いです。

// 例constpokemon={name:"サニーゴ",region:"ガラルちほう"};consttypeCheck=sunnygo=>{consttype=sunnygo.region==="ガラルちほう"?"ゴースト":"みず・いわ";return`サニーゴは${type}タイプです`;};console.log(typeCheck(pokemon));// 出力結果は"サニーゴはゴーストタイプです"

三項演算子を使わずにこれを記述すると、以下のようになります。

constpokemon={name:"サニーゴ",region:"ガラルちほう"};consttypeCheck=sunnygo=>{lettype;if(sunnygo.region==="ガラルちほう"){type="ゴースト";}else{type="みず・いわ";}return`サニーゴは${type}タイプです`;};console.log(typeCheck(pokemon));// 出力結果は"サニーゴはゴーストタイプです"

else文だと、コードのブロックが増えていたり、関数の上部でletを宣言してから再代入をするような書き方を余儀なくされたり、少し「すっきり」ではなくなっている、という感覚を掴んでいただけるかと思います。

短絡演算子

&& (論理AND) や || (論理OR)といった論理演算子を用いたショートカットの構文も、条件分岐の一種として活用することができます。構文は以下の通りです。

値A || 値B
 値Aがfalseの判定の場合、値Bが判定される 

値A && 値B
 値Aがtrueの判定の場合、値Bが判定される
constletsGo=pokemon=>{constpartner=pokemon||"イーブイ";returnpartner;};console.log(letsGo("ピカチュウ"));// 出力結果は"ピカチュウ"console.log(letsGo(null));// 出力結果は"イーブイ"

上の例では、引数pokemonがfalsyな値(false, 0, -0, NaN, null, undefined, 空文字列(""))だった場合に、必ず"イーブイ"を戻り値にする関数が実行されています。

条件がfalsyだった場合、デフォルトの返り値を短いコードで表現する際に、よく用いられる書き方です。

この書き方が見慣れない方は、以下のコードを見てもらえば挙動のイメージがつくかと思います。

constletsGo=pokemon=>{if(!pokemon){return"イーブイ";}returnpokemon;};

ちなみに、短絡演算子ではfalsyな値を全て一律に評価するので、たとえば引数がundefinedの時のみデフォルトを返すようにしたい、というような場合は、以下のように書く必要があります。

constletsGo=pokemon=>{constpartner=pokemon===undefined?"イーブイ":pokemon;returnpartner;};console.log(letsGo());// 出力結果は"イーブイ"console.log(letsGo(null));// 出力結果はnull

すっきりな条件分岐を考える

JavaScriptの主な条件分岐の書き方をおさらいしたところで、ここから「可読性が高く」、「バグが生まれにくく」、「後からリファクタリングがしやすい」、すっきりした条件分岐の書き方を追求します。

結論から言うと、本記事の主張は以下の3点です。

  • ショートカット演算子は使いどころをきちんと定め、多用しないようにする
  • 実践のコーディングでelseは使わなくてよい
  • 複数の条件分岐はswitch以外の書き方も覚えておくこと

何でもショートカット演算子、ではNG

三項演算子や短絡演算子は、一行で条件分岐が記述できる便利な構文のため、つい多用してしまいがちになりますが、何にでも使えばいいというわけではなく、かえって可読性を下げてしまう場面もあります。

constsunnygo={region:"カントー地方"};constisGalar=sunnygo=>{returnsunnygo.type==="ゴースト"||""?true:sunnygo.type="みず・いわ";};isGalar(sunnygo);console.log(sunnygo.type);// 出力結果は「みず・いわ」

上記のコードでは、引数sunnygoのtypeプロパティが"ゴースト"という文字列か空文字だった場合はtrueを、それ以外の場合はtypeの値を"みず・いわ"にする、というような関数を無理やりショートカット演算子で1行にして記述していますが、何が返ってくる関数なのかが一目で分かりづらいことになっていますね。

(実際にこんなコードを書く人はいないと思いますが、あくまで「やろうと思えばこういうことが出来てしまう」という悪い例なので大目に見てください……。)

入り組んだ条件分岐は、素直にifで書きましょう。

constsunnygo={region:"カントー地方"};constisGalar=sunnygo=>{if(sunnygo.type==="ゴースト"||""){returntrue;}return(sunnygo.type="みず・いわ");};isGalar(sunnygo);console.log(sunnygo.type);// 出力結果は「みず・いわ」``

elseって必要?

個人的に、elseは使わなくても良い、と考えています。私は実務のコーディングでelseを書いたことがありませんが、その理由がelseがどうしても必要になる場面がないからです。

elseは分岐の条件を書かないため、else節の処理の意味がつかみづらくなるという短所があります。単に「if節の条件がfalseの場合」を強調したいなら三項演算子で良く、そうでなくとも、if節でreturn文を書いてif節の外でデフォルトの値をreturnする、という風に書けば良いので、ブロックを増やしてまでelse節を記述する必要はないのです。ifとそれ以外、という条件の分け方を行う場合、else節は無くても大丈夫です。

else ifについても同様で、else ifを使いたい場面では、たいていswitch文を使うか、ifをひとつずつ書いていく方が「すっきり」する場合が多いです。

else文はコーディングの勉強で活用するにとどめ、実践ではelseを書かないクセをつけると良いかと思います。

switchばかり使うのは危険?

複数の条件分岐を書こうというときにswitch文は非常に便利な構文ですが、switchしか解決法を持っていないと、しばしば困る場面も訪れます。

先述のとおり、switchはbreakの仕様のおかげで、気をつけないとバグを生んでしまう構文です。また、3~4ケースの条件分岐ならあまり気になりませんが、分岐が100ケースを超えたりすると、switchだと非常に読みづらいです。

constpokemon={name:"ニャース"};constpokemonIndex=pokemon=>{switch(pokemon.name){case"フシギダネ":return1;case"フシギソウ":return2;case"フシギバナ":return3;case"ヒトカゲ":return4;case"リザード":return5;case"リザードン":return6;case"ゼニガメ":return7;case"カメール":return8;// 以下、図鑑No.151まで続く...}};

上記は、ポケモンの名前に応じた図鑑ナンバーを返すプログラムを書こうとしているところなのですが、switchで151ケース(default含めると152ケース)の条件分岐を行うことがいかに無謀なことなのかは、何となくお分かりいただけるかと思います。。

しかも、この書き方だとポケモンに少し詳しい人じゃないと図鑑ナンバーのことを言っていることが伝わりづらい。。

こうした時のために、switch以外で複数の条件分岐を書く術も、いくつかあると良いでしょう。

私がよく使っているのが、find関数を用いた条件分岐です。

Array.prototype.find
array.find( callback関数() )

これは、配列の要素それぞれに対してコールバック関数を実行し、最初にtrueな値を返すという関数です。もちろん、本来は配列を扱うための関数なのですが、これを活用することで、たとえば以下のように条件分岐を書くことができます。

constpokemonList=[{name:"フシギダネ",No:1},{name:"フシギソウ",No:2},{name:"フシギバナ",No:3},{name:"ヒトカゲ",No:4},{name:"リザード",No:5},{name:"リザードン",No:6},{name:"ゼニガメ",No:7},{name:"カメール",No:8},{name:"カメックス",No:9},{name:"キャタピー",No:10},{name:"トランセル",No:11},{name:"バタフリー",No:12},// 以下、図鑑No.151まで続く];constpokemon={name:"ニャース"};constpokemonIndex=pokemon=>{constpokemonNumber=pokemonList.find(p=>p.name===pokemon.name).No;returnpokemonNumber;};console.log(pokemonIndex(pokemon));//出力結果は52;

上記のコードでは、配列pokemonListに分岐の対象となっているポケモンの名前と図鑑ナンバーのセットを格納し、関数pokemonIndexで、引数に指定したポケモンの名前とpokemonListに格納されたnameが一致するまで配列内で検索を行い、配列で最初に一致した値を返しています。

switchで書く場合と比較して、objectとして要素を扱うのでコピペがしやすかったり、ページ内検索がかけやすかったりするため、リファクタリングのしやすさが格段に上がっていることがお分かりいただけたら幸いです。これなら、ある日突然、全国図鑑になったとしても充分に対応できます。

まとめ

  • else文:使わなくても平気
  • switch文:便利だけど、ときに不便
  • 三項演算子:変数の代入でサクッと条件分岐したいときに使おう
  • 短絡演算子:デフォルトの値を明示したいときに使おう
  • find関数は良いぞ

JavaScriptには色々な構文がありますが、それぞれの長所・短所を踏まえつつ、すっきりしたコーディングを目指していけると良いのかな、と思います。

以上です。
間違い、不足点の指摘などあれば、コメントをお願いいたします。

AWSにdjangoでWebアプリを立ち上げて転職

$
0
0

こんにちはmogkenです。

前回Python+Django+AWSでスクレイピングアプリを作って転職という記事を書いてから3ヶ月余りが経ちました。タイトルの通り幸いにも転職が成功して1月からクラウド基盤を開発している会社にサービス企画で転職しました(^o^)/

というわけで今回はその時に作ったPythonのwebアプリをAWSに構築した際の手順を簡単に記録します。ただ申し訳ないのですが随分と前のことなので、やや記憶が曖昧で内容が正しいか保証できません...素人の備忘録だと思ってください。

今回のやること

AWSのVM(Centos7)にpython3とDjango、nginx、そしてgunicornをインストールして、作成したWebアプリをデプロイします。ロードバランサーやオートスケーリングもやろうと思っていたのですが、転職ができてしまったので一番簡単な構成で力尽きました...

構成図(最小構成すぎるのでいらないけれど一応)
スクリーンショット 2020-02-12 17.54.50.png

AWSの設定

この構成でAWSで設定すべき項目は大雑把に書くと以下の通り

  1. ネットワークの作成
  2. VMの作成
  3. DNSの設定

なお詳しい手順はここでは記載しない。だって素人のしかもうろ覚えの手順なんてとても怖くて参考にできないでしょう。

参考URL:https://qiita.com/okoppe8/items/dc1de147a36797442e4c

1.ネットワークの作成

AWSではまずVMを立ち上げるためのVPCを作成する必要がある。

流れは次の通り

  1. VPCの作成
  2. サブネットの作成
  3. インターネットゲートウェイの作成
  4. ルートテーブルの作成
  5. セキュリティグループの作成

2.VMの作成

アプリケーションを構築するためのVMを作成する。でもやることはただEC2をボタンをポチポチして作成するだけ。

3.DNSの設定

公開するためのドメインの設定をAWSのDNSサービスであるRoute53を使って行う。

自分はこのサイトを参考に行った。

https://avinton.com/academy/route53-dns-vhost/

Linuxサーバの設定

AWSでVMの作成が終わったら次は立ち上げたVMの設定を行う。

ここからは少し詳しく解説する。(何回も失敗して繰り返したから割と記憶が鮮明なのだ...)

あとはここからの設定は基本的には

https://narito.ninja/blog/detail/21/#_3

このページを参考にしている。このブログはDjango周りのとてもわかりやすい記事がたくさんあるので、とてもオススメ。

手順としては次の通り

  1. 立ち上げたVMにSSH or Webコンソールでログイン
  2. python3のインストール
  3. djangoのインストールと設定
  4. nginxのインストールと設定
  5. gunicornのインストール
  6. サービスの立ち上げ

1. 立ち上げたVMにSSH or Webコンソールでログイン

EC2の作成時に同時にsshでアクセスするための認証鍵も作成されるから、それをダウンロードして使用する。何を言っているのかわからない人はAWSのコンソール画面からもWeb上でVMにアクセスできるのでそちらでやってみると良いかもしれない。

ダウンロードした認証鍵はそのまま使おうとすると、認証鍵の権限がオープンすぎると怒られるため次のコマンドでファイル権限を設定する必要がある。

chmod 400 "ダウンロードした認証鍵ファイル名"

あとは以下のコマンドでsshアクセスができる。

ssh -i "***.pem" ec2-user@"EC2のパブリックDNS名 or パブリックIP"

2. python3のインストール

参考URL:https://qiita.com/s_runoa/items/156f3fa67c82e9cd9f42

ここからは必要なパッケージをインストールしていく。まずはpython。pyenvを使っているけれど未だにpyenvが何か正確には分かっていない...

#yumパッケージのアップデート
yum update -y

#必要パッケージのインストール
sudo yum install git gcc zlib-devel libffi-devel bzip2-devel readline-devel openssl-devel sqlite-devel

#pyenvのインストール
git clone https://github.com/yyuu/pyenv.git ~/.pyenv

#.bash_profileに追記
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

**ここでサーバを再起動**

#Pyhtonのインストール
pyenv install --list
CFLAGS="-fPIC" pyenv install 3.7.2

#pythonの設定
pyenv versions
pyenv global 3.7.2
pyenv rehash

#インストールの確認
python --version

3.djangoのインストール

pythonがインストールできたらdjangoをインストールする。ちなみに自分にとっての初フレームワークがdjangoなので、djangoにはなんだかとても特別な気持ちを抱いている。

#djangoのインストール
pip install Django

以上でdjangoのインストールは終了なのだが、あとでsqlliteのバージョンが古いと怒られることになるのでここでその対策もしてしまうと良いと思う。

怒られないこともあるから、めんどくさい人は飛ばしてしまって本当に怒られてからやってもよい。

Sqlliteのアップグレード

参考URL:https://qiita.com/rururu_kenken/items/8202b30b50e3bfa75821

#tarファイルの取得
wget https://www.sqlite.org/2019/sqlite-autoconf-3280000.tar.gz

#tarの解凍
tar xvfz sqlite-autoconf-3280000.tar.gz

#ビルドしてインストール
cd sqlite-autoconf-3280000
$ ./configure --prefix=/usr/local
$ make
$ sudo make install
$ sudo find /usr/ -name sqlite3


$ sudo mv /usr/bin/sqlite3 /usr/bin/sqlite3_old
$ sudo ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3

# 共有ライブラリへパスを通す
$ export LD_LIBRARY_PATH="/usr/local/lib"

setting ファイルの編集

Djangoを正常に立ち上げるための最低限の設定をここで行う。

#djangoプロジェクトの作成
django-admin startproject "プロジェクト名"

#djangoアプリの作成
python manage.py startapp "アプリ名"

#設定ファイルの編集 djangoの設定ファイルはプロジェクト名と同じ名前のフォルダに作られる
vi /"プロジェクト名"/"プロジェクト名"/setting.py

#以下setting.pyの中の編集項目
#installed_appの末尾に追加
"アプリ名".apps."アプリ名(頭文字を大文字にする)"Config
例)'myapp.apps.MyappConfig'

#デバッグの非表示とhostの指定
DEBUG = False
ALLOWED_HOSTS = ["設定したドメイン名"]

#言語とタイムゾーンの設定
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'

#静的ファイルの置き場の設定
STATIC_URL = '/static/'  # これは元からあります。
STATIC_ROOT = '/usr/share/nginx/html/static'
MEDIA_URL = '/media/'
MEDIA_ROOT = '/usr/share/nginx/html/media'

#保存してsetting.pyの編集終了

#最後にこのコマンドを打って終了
sudo python manage.py collectstatic

4.nginxのインストールと設定

WebサーバにはNginxを使う。初めてこれに出会った時にどうやって読むのか皆目分からなかった。

nginxのインストール

#nginxのインストール
sudo amazon-linux-extras install nginx1.12

nginxの設定

#設定ファイルのの編集
sudo vim /etc/nginx/conf.d/project.conf

#以下設定項目
server {
    listen  80;
    server_name "サーバのパブリックIPアドレス";

    location /static {
        alias /usr/share/nginx/html/static;
    }

    location /media {
        alias /usr/share/nginx/html/media;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

#保存して終了

#設定ファイルチェック
sudo nginx -t

#nginxの起動
sudo systemctl reload nginx

#サーバ起動時に同時にnginxも起動するための設定
sudo systemctl enable nginx

5.gunicornのインストール

最後にwsgiとしてgunicornをインストールする。wsgiもgunicornも名前からしてなんだか良く分からない...

sudo pip3.7 install gunicorn

これだけで終了。なんとも簡単。

サービスの立ち上げ

最後にサービスを立ち上げる

#manage.pyのファイルが置かれているプロジェクトフォルダに移動
cd /project

#gunicornの起動
sudo gunicorn --bind 127.0.0.1:8000 project.wsgi:application

ここまでやったらドメイン名でdjangoのプロジェクトのアクセスできるようになっている。

最後にgunicornを止めたい場合の設定をのせておく

#gunicornのプロセス番号の確認
lsof -i:8000

#表示されたプロセスをkill
kill -9 "表示されたプロセス番号"

おつかれさまでした。

色々なエラーと闘って最後にページが立ち上がった瞬間はとても嬉しかった。
なんだか少し大人になったような気がした。

Viewing all 21069 articles
Browse latest View live