Technology Engineering

178inaba の技術ブログ

Raspberry Pi(Raspbian)の更新

新しいRaspberry Piを買ったので、ついでに以前GitLabを入れたRaspberry Piの更新をした。

# パッケージリスト更新
$ sudo apt-get update

# パッケージ更新
$ sudo apt-get dist-upgrade

# ダウンロードしたパッケージの削除
$ sudo apt-get clean

sudo apt-get dist-upgradeは結構時間かかる。

GitLabもRaspbian版は長らくバージョン8.7.9で止まっていたのだが、最近更新されてバージョン9.0.2が使えるようになっていた。
Dockerレジストリも使えるようになった。

参考:

www.raspberrypi.org

gitlab.com

Herokuアプリとgitからcloneしたアプリの紐付け

Herokuアプリを1から作る時はheroku createだけど、既に存在するHerokuアプリとgitからcloneしたアプリを紐付ける方法がわからなかったので調べた。

$ heroku git:remote -a app_name

これでリモートにherokuが追加される。

$ git remote -v
heroku  https://git.heroku.com/app_name.git (fetch)
heroku  https://git.heroku.com/app_name.git (push)
...

参考:

stackoverflow.com

別環境で作ったRailsプロジェクトを新しい環境に持ってきたときの環境構築

今日は近くの公民館の自習室でRailsチュートリアルをしてました。

帰ってきてからRails環境が無いPCで続きやろうとしてgit cloneの後、ちょっと躓いたのでその時の事をメモとして残しておきます。

Rails環境構築

macOSRailsの環境構築してローカルサーバ起動するまで。

# Rubyをbrewでインストール
$ brew install ruby

# NokogiriのGemをインストール
$ gem update --system
$ xcode-select --install
$ gem install nokogiri

# RailsのGemをインストール
$ gem install rails

# Railsプロジェクトをクローン
$ git clone https://github.com/user/rails-project.git

# プロジェクト固有のGemをインストール
$ cd rails-project/
$ bundle install

# DB構築
$ bin/rails db:migrate

# ローカルサーバ起動
$ bin/rails server

Gemfile.lockがあったらbundle installすると覚えておけば良い。
bundleコマンドはgem install railsRailsの依存Gemとしてインストールされる。

bin/rails db:migrateも意外と忘れがちなので注意。

Railsのインストールでエラーが出たらNokogiriを先にインストールしよう

Railsのチュートリアルをやっているのですが、Railsのインストールで躓きました。

$ gem install rails
...
xmlIO.c:1450:52: error: use of undeclared identifier 'LZMA_OK'
...

Nokogiriのインストールでエラーです。

issueも立っていました。

github.com

解決法

NokogiriのmacOS用のインストール手順に従って

$ gem update --system
$ xcode-select --install
$ gem install nokogiri

とするとNokogiriがうまくインストールされます。

Nokogiriがインストールされた後にRailsをインストールするとエラーも出ません。

$ gem install rails

Railsのインストールでエラーが出る人はお試しあれ。

『ボトルメール』というLINE Botを作っていた話。 #BOTawards

inabaです。

忙しくてブログにまとめるのが遅れていまいましたが、2月末にLINE Botを作ってLINE BOT AWARDSにエントリーしてました。

https://bottle-mail.178inaba.com/bottle-mail.178inaba.com

ボトルメールといいます。
Botと友達になってメッセージを送るとBotと友達になっている人の中でランダムにメッセージが飛び、その人と会話できるBotです。
「おわり」とメッセージを送って返ってきた確認ダイアログで「終了」を押すか、1時間メッセージが飛んでいないと会話が終了になります。

2月26日に作り始めて、半ば徹夜のような形で作っていたため告知できませんでした(=_=)
(開発自体は2月28日までに終わってましたよ!マジで!!)
このBot自体の友達が多くないと意味が無いので多分賞に選ばれることは無いと思いますw
まぁ勉強だと思って作りましたので、よかったら友だちになってやってください!

https://qr-official.line.me/M/S3fUYbyDh8.png

LINE BOT AWARDSの結果でた後くらいにはソースを整理してGitHubに上げようと思ってます。

何かあればコメントやツイッターにでもご意見頂ければうれしいです。

よろしくどうぞ〜

2018/11/11追記

こちらのサービスはクローズしました。

golang.tokyo #4に行ってきた。 #golang #golangtokyo

inabaです。

golang.tokyo #4に補欠からの当日滑り込み繰り上がりという運の良さで参加してきました。
会場はペアーズの株式会社エウレカさん。

倍率が2倍ということもあり、狭き門という印象のgolang.tokyoですが、今回から動画撮影も始まったようです。
次回のgolang.tokyoの前あたりに公開されるそうです。
自分も#2,#3と2回補欠だったのでこれは助かりますね!!

また、@tenntennさんからブログ枠の紹介がありました。
毎回3名分のブログ枠が用意されていて、

  • 先着順なので参加確定
  • まとめることで頭の中の整理になる
  • connpassの資料のページに掲示されるので多くの人にブログを見てもらえる

のが主なメリットだそうです。

今回はConcurrency(コンカレンシー、並行性)がテーマでした。
今回はブログ枠で参加ではないですが、ブログ枠で参加するときのためにまとめてみます。

Concurrency for distributed Web crawlers

末田 卓巳さん (@puhitaku) / フラー株式会社

WebクローラーのためのGo言語の話です。

  • アプリのデータをストアからクローラーで24時間毎に取ってくる。
    • 単一のサイト(シングルドメイン)なので間隔が短いとBANされる可能性がある。
    • 10万以上のアプリのデータをクロールする。
    • 画像のダウンロードがあるので1回のクロール時間が異なってくる。
  • コマンダークローラーから構成されるクロールプログラム。
  • 1回のクロール時間が異なるので、例えば100回クロールする2個のクローラーがあっても直列で実行すると処理終了時間がまちまちになる。
    • Goroutineを使って時間をずらして並行に実行していくと実行時間が同じになる。

f:id:i178inaba:20170302021108p:plain

  • SlackBotとしても動いている。
    • クローラのステータスを通知させる目的。
    • 普通のSlackBotは1回コマンドを打つと1回返答が返ってくる。
      • これだと何回もコマンドを打たないとならなくて面倒。
    • クローラーに実装されているSlackBotはSlackの編集機能を使う。
      • コマンドを受けた最初の投稿は普通に。
      • 次の投稿から編集機能を使用し、最初の投稿を編集する。
    • 普通の投稿か編集かの判断をしてPostをするGoroutineと投稿する文字列を生成するGoroutineが分けてあり、chanで通信している。

f:id:i178inaba:20170302022728p:plain

  • 並行処理時のTCPコネクションの枯渇問題
    • DBからデータを吸い出すのも並行で行っている。
    • 何らかの理由でqueryが遅く、並行処理が重なってしまいTCPコネクションを使い果たしてエラーが出ることがある。
    • それを防ぐため、バッファサイズを指定したchan(make(chan int, 100))を使用して一度に処理する回数を制限する。
    • 制限中にGoroutineが1つ終了するとブロックされていたchanのブロックが解除され、次のGoroutineが動作する仕組み。

Slackの編集機能をBotに使わせるというアイデアには「その手があったか!」と目からウロコでした!

Goのスケジューラー実装とハマりポイント

井手 康貴さん (@niconegoto) / 株式会社メルカリ/株式会社ソウゾウ

https://talks.godoc.org/github.com/niconegoto/talks/concurrency.slide#1

参考記事: qiita.com

The Go scheduler - Morsing's blog

  • GoroutineはOSスレッドに対して多対多。
    • 1対1、多対1に比べて全てのコアを使えてコンテキストスイッチも高速でいいとこ取り。
    • ただし、スケジューラーへの追加が煩雑になる。
      • Goはこの煩雑さをラップしていて、簡単(go f()と書くだけ。)にGoroutineが使えるようになっている。
  • 用語(runtimeパッケージ以下を読む時に覚えておくと役に立つ。)
    • M(Machine): OSスレッド
    • G(Goroutine): ゴルーチン
    • P(Processor): プロセッサ。4コアなら4
  • Pは自分にスケジューリングされたGが無くなると、別のPからGを半分奪う。
    • これにより、全てのスレッドが最大パフォーマンスで動作できる。
  • runtime.GOMAXPROCS()が1でもGoは複数のスレッドで実行される。
  • ハマりどころ
    • ループしてGoroutine外の変数を参照する場合。
    • runtime.GOMAXPROCS()が大きいほど切り替わりやすくなる。

今までなんとなく使っていたgo f()の仕組みがとてもわかりやすく理解できました。

Ridge - A framework like GAE/Go on AWS

藤原 俊一郎さん (@fujiwara) / 株式会社カヤック

GAE/GoをAWSで動かすためのフレームワークの話です。

  • 下記を使用
    • APEX
      • 通常、LambdaでGoを実行することはできないが、APEXを経由させることにより実行できる。
    • AWS API Gateway
    • AWS Lambda
    • Go
  • API Gateway × Lambdaのデメリット
    • 独自オブジェクト
    • ルーティング・・・
    • テスト・・・
    • Goで書きたい!
  • Ridgeが行う事
    • API Gateway(JSON)とnet/http(Request, Response)の相互変換
    • Lambdaで動かさない時は通常と同じくサーバとして立ち上げられる。
  • 流れはリクエスト→API GatewayAWS Lambda→APEX→Go(Ridge→Handler)
  • メリット
    • 独自オブジェクトではなく、いつも使っているRequest/Responseが使える
      • Request/Responseで書くからテストにhttptestが使える。
    • ルーティングもGo内で行える。
    • ローカルで動かせるからlocalhostを叩いて結果を受けるとかができる。
    • EC2でも普通に動かせる。
    • API Gateway × Lambdaのメリットが享受できる。
      • 高負荷時自動スケール
      • EC2の管理無し!
      • デプロイもコマンド一発。
      • つまりGAE/Go!
  • できないこと
    • 同一名クエリ(foo=a&foo=b)や同一名ヘッダが受け取れない。
    • バイナリ(画像等)が返せない。
    • Goroutineを動かし続ける
    • 1リクエスト10秒を超える処理
  • 向いていない事
    • 低レイテンシが要求されるような処理
  • 向いている事
    • 頻繁にアクセスが無い。
    • レイテンシ要求がシビアでない。
      • ChatBotやゲームの終了告知(POSTを受けてJSONを返す)等
  • ログはCloudWatch Logsに送られるが、それをLambdaに送ってRidgeでパースしている。

github.com

既存のWebアプリもちょこっといじってmux.HandleFuncを使うようにするだけでハンドラの中身を変えなくてもRidgeを使い始められるのがすごいですね!
制限はありますが、ChatBotくらいから試しに使ってみるのはいいかもしれません。

懇親会

途中、ピザとビールが出る懇親会がありました。

美味しかったです!ごちそうさまでした!!

Goを使ったtailコマンドの実装(ライブコーディング)

金子 慎太郎さん (@kaneshin0120) / 株式会社エウレカ

コード: https://gist.github.com/kaneshin/a398720b8e20722a83bc6903e4017435

発表予定だった牧さんが残念ながら都合がつかず来られなくなってしまったため、急遽かねしんさんがライブコーディングをすることに。
懇親会しながらも、みんなの目線はスクリーンに釘付けでした。
tenntennさんのツッコミも入りつつ、かなり盛り上がっていました。

嫁に怒られずにGoを書く技術

@teitei_tkさん / freee株式会社

嫁だけでなく、非エンジニアの友人駆動開発にも使えますね。
嫁が居ないのでそんなことを考えてました(泣)
質問の時、tenntennさんが
「質問無いですか?」
「嫁はどうやって作るんですかとかでもいいですよ。」
「ペアーズ使いましょう!」
と自分でツッコんで会場が沸いてましたwww

Gogland

Sergey Ignatovさん (@sergey__ignatov) / JetBrains

JetBrains製のIDEの紹介です。

英語だったので必死に聞きましたが半分はツイッター#golangtokyoを追っていました。
何件か気になるツイートを紹介します。

自分は、こういうのどうやって作るんだろうっていうのを考えながら見ていました。

まとめ

ブログを書くのは結構大変だけど、頭の中が整理できるのでおすすめです。
長めに書いてしまったのは反省点で、今後はもうちょっとまとめられるようにしていきたいと思います。

運営の皆さんご苦労様でした!!
また参加させて頂きます!!

CentOS 7のファイアウォールで80番ポートを許可する

inabaです。

サーバにnginxをインストールして、localhostからはアクセスできるのに、外部(グローバルIPや設定したドメイン)からはアクセスできなくて困っている人はファイアウォールの設定を疑ってみるとよいです。

firewall-cmd

ファイアウォールを操作するコマンドです。

www.firewalld.org

コマンドの使い方を全て覚えるのは大変なのでポート許可に必要な使い方を紹介していきます。

アクティブなゾーンを確認する

ファイアウォールは「事前に定義されたゾーンに対して、指定されたルールの通信を通す。」という事をしています。
なので、まずはどのゾーンへのファイアウォールが動いているかを確認します。

$ firewall-cmd --get-active-zones
public
  interfaces: eth0

--get-active-zonesというオプションをつけると、現在アクティブなゾーンが表示されます。

上記だとpublicというゾーンがアクティブな事がわかります。
複数ある場合は、eth0が外部公開されているインタフェースなのでeth0が定義されているゾーンが外部向けポートを追加する対象になります。

許可されているポートの確認

次は先程確認したアクティブなゾーンpublicの確認です。
現在許可されているポートを確認します。

$ firewall-cmd --info-zone public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  sourceports:
  icmp-blocks:
  rich rules:

servicesには定義されているサービス(ルールのような物)が表示されます。
portsにはサービスとは別に開放されているポートが表示されます。
今回はportsには何も表示されていませんが、例えば8080番ポートが開放されていると、ports: 8080/tcpのように表示されます。

上の例だとservicesにdhcpv6-clientとsshが設定されています。

サービスの内容を確認します。

$ firewall-cmd --info-service dhcpv6-client
dhcpv6-client
  ports: 546/udp
  protocols:
  source-ports:
  modules:
  destination: ipv6:fe80::/64
$ firewall-cmd --info-service ssh
ssh
  ports: 22/tcp
  protocols:
  source-ports:
  modules:
  destination:

portsに開放されているポートが表示されます。
dhcpv6-clientでは546番ポート、sshでは22番ポートが開放されています。

定義されているサービスを確認

サービスの一覧は--get-servicesオプションで確認できます。

$ firewall-cmd --get-services
RH-Satellite-6 amanda-client amanda-k5-client bacula bacula-client ceph ceph-mon dhcp dhcpv6 dhcpv6-client dns docker-registry dropbox-lansync freeipa-ldap freeipa-ldaps freeipa-replication ftp high-availability http https imap imaps ipp ipp-client ipsec iscsi-target kadmin kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mosh mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy proxy-dhcp ptp pulseaudio puppetmaster radius rpc-bind rsyncd samba samba-client sane smtp smtps snmp snmptrap squid ssh synergy syslog syslog-tls telnet tftp tftp-client tinc tor-socks transmission-client vdsm vnc-server wbem-https xmpp-bosh xmpp-client xmpp-local xmpp-server

結構量が多いのですが、この中にhttpというそれっぽいサービスを見つけることができます。
httpサービスの内容を確認します。

$ firewall-cmd --info-service http
http
  ports: 80/tcp
  protocols:
  source-ports:
  modules:
  destination:

ビンゴです!
80番ポートがルールとして定義されています。

サービスをゾーンに追加

httpサービスが80番ポートを開放するサービスという事がわかったので、publicゾーンにhttpサービスを追加します。

$ firewall-cmd --permanent --zone public --add-service http
success
$ firewall-cmd --reload
success

--permanentは設定の永続化。(無いと再起動時に設定が消えます。)
--zone publicはゾーンの指定。
--add-service httpは追加するサービスの指定です。

--add-serviceだけでは設定が反映されないので、設定をした後に--reloadファイアウォールに設定を反映させます。

$ firewall-cmd --info-zone public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: dhcpv6-client http ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  sourceports:
  icmp-blocks:
  rich rules:

設定が反映されました。

サービスに許可したいポートが無い場合

例えば8080等のポートを開けたい場合があると思います。
しかし、サービスには一般的に使用されているポートしか定義されておらず、8080番のポートは定義されていません。
そういう場合は--add-serviceの代わりに--add-portを使います。

$ firewall-cmd --permanent --zone public --add-port 8080/tcp
success

このような感じです。

今日はここまで。