ネットワーク関連メモ

イベントにネットワークの運営側として参加したので勉強になったことメモ

もっと詳しくなりたい...

Wireless LAN Controller と Access Point

Access Point は、Wifiを飛ばしたい場所に直接置く。

これを有線でインターネットに接続して、かつWireless LAN Controllerと接続しておけば、Wireless LAN Controller上から、全てのAccess Point の管理ができるのでめっちゃ便利! 離れた場所のAccess Point も一括管理可能!

例えば、システムのアップデートや、Access Point のステータス、Access Pointに繋がってる人数など。

Access Point の設置

Router -> 各部屋のPatch(LAN ケーブル繋げるところ)-> LAN ケーブル -> Switch(VLANに対応している必要があるとのこと。) -> LAN ケーブル -> Access Point と配置する。

各部屋にどのくらい、どの場所でAccess Point を置く必要があるかは、人数とか他の配置物とか、電源とかによる模様。

電源はSwitchからAccessPointに供給される。 PoE(Power over Ethernet)を使えば、電源ではなく、LANケーブルから電源供給できるので便利。

VLANの概要と基本的な仕組み https://news.mynavi.jp/article/vlan-1/

Wifi について

Access Point から、Wifi が飛ぶようになっていて、5ghzと、2.4GHzの帯域で飛んでいる。

2.4GHz は遮蔽物に強く、遠くまで届くが、通信速度が遅く、電子レンジとかbluetooth と同じ帯域なので混線しやすい。

一方、5GHzは遮蔽物に弱いが、通信速度が早く、混線もしにくい。

そのため、各部屋毎にAccess Point を設置しておくと、みんなが5GHz のWifiを使って、高速な通信が可能。

会場が元々提供している5GHzや2.4GHzの帯域がある場合、2.4GHzはチャンネル数、いわゆる通信ができる通路が少ないため、干渉する可能性があり、この点からも5GHzを使うことが良い。

ただ、5GHzは、気象レーダーや軍事レーダーでも使われている帯域のため、屋外での利用は難しいらしい。部屋の中で使うのは問題ない。

Wireless LAN Controller の監視

SNMPというプロトコルを用いて、zabbixを用いて監視する。

可視化はGrafanaを用いるとかっこいい!

多分こんな感じ。

https://qiita.com/k7tak29/items/dd0961cf9fc1ef3301a7

Nuxt + Express + Nginx with Docker 作成

目的

Nginx, Nuxt, Express を用いたDocker環境を作成した。 Nginxを用いる理由は、アクセスログをnginxにやらせたかったからで必須ではないです。 envoy?的なイメージ。

設定関連

Nginx

unix socketでExpressと通信をするようにする。 ポートでも問題ないけど、試して見たかったのでunix socket を利用してみた。

nginx.confこんな感じ。

upstream nuxt_app {
  server unix:/app/tmp/nuxt.sock;
}

server {
  listen 80;
  server_name ${SERVER_NAME};

  access_log stdout;
  error_log  stderr warn;
  access_log /app/log/access.log tsv;
  error_log  /app/log/error.log warn;

  location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;

    proxy_pass http://nuxt_app;
  }
}

Nuxt & Express

app/tmp をvolume マウントして、Nginxから見られるようにすることで、unix socketによる通信を可能にしてます。 DockerFileはこんな感じ。

FROM node:11.8.0-alpine
ENV LANG C.UTF-8

RUN mkdir /app
WORKDIR /app

ADD . /app

VOLUME /app/tmp

RUN npm i -g yarn
RUN yarn install --production

ARG ENV
RUN yarn nuxt build
CMD node server/index.js

チュートリアル通り、nuxtをセットアップして、server.js をunix port でlistenするようにする。 EC2だと、pm2使ってたが、dockerだとなくていいらしいので楽!

参考

Node.jsをunix domain socketでlistenしたときにNginxからプロキシできない - なっく日報

async function start() {
  ...省略
  app.use(nuxt.render);

  // Listen the server
  const socketPath = '/app/tmp/nuxt.sock';
  // 必要ならここで既にsockファイルが存在する場合削除が必要かも。
  app.listen(socketPath, (err) => {
    if (err) throw err;
    fs.chmodSync(socketPath, 660);
    consola.ready({
      message: `Listening on socket`,
      badge: true
    });
  }
}
start();

docker-compose

こんな感じ。

version: '2'
services:
  app:
    build:
      context: .
      args:
        ENV: ${ENV}
    env_file:
    - .env

  nginx:
    build: nginx
    ports:
    - "80:80"
    volumes_from:
    - app
    env_file:
    - .env
    depends_on:
    - app

Nuxt & Docker 開発環境構築

目的

Nuxt(SSR)をDockerで開発をスムーズにできるように、雛形作ったのでメモ

レポジトリ

github.com

説明

READMEに書いたけど、いつか消すかもなので、こちらにもメモ

初期手順

terminalから、以下を実行すると、dockerにnodeをインストールした環境ができる。

$ docker-compose -f docker-compose.init.yml up -d
# 「builder_nuxt_1」は、container nameで、dokcer ps で確認できるので、自分の環境と合わせて。
$ docker exec -it builder_nuxt_1 sh

これで、dockerの中に入れるので、dockerの内部で、nuxtをinstall

$ yarn create nuxt-app .

# こんな感じに回答する。
> Generating Nuxt.js project in /app
? Project name app
? Project description My mind-blowing Nuxt.js project
? Use a custom server framework express
? Choose features to install Linter / Formatter, Prettier, Axios
? Use a custom UI framework none
? Use a custom test framework none
? Choose rendering mode Universal
? Author name
? Choose a package manager yarn

# install終わったら、installしたものが、localにコピーされてるはず。
# 一回dockerから出る。
$ exit

実際の開発をするためのコンテナを起動する。

$ docker-compose up -d --build

これで、localhost:3000 で、nuxtにアクセスできる。

開発時

毎回、コマンド打つの面倒だから、makeコマンドを利用する。

# こんな感じで起動できる。
$ make start

# バグったらこれ試してみる
$ make rm_node_modules
$ make restart

注意: 初期手順後すぐに make コマンドを利用する時は、一回下のコマンドで、立ち上がってるdockerを殺す。

$ docker-compose kill
$ docker-compose rm -f

よく使うpackage

エディターについて

Vue開発においては、vscodeがおすすめ!

{
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    {
      "language": "vue",
      "autoFix": true
    }
  ],
  "editor.formatOnSave": true,
  "prettier.eslintIntegration": true,
  "eslint.autoFixOnSave": true
}
{
  "recommendations": [
    "octref.vetur",
    "esbenp.prettier-vscode",
    "eamodio.gitlens"
  ]
}

これをrootディレクトリに置くと、component へコードジャンプできる!

{
  "include": ["./components/**/*"],
  "compilerOptions": {
    "module": "es2015",
    "baseUrl": ".",
    "paths": {
      "~/components/*": ["components/*"]
    }
  }
}

Nuxt 2.4.0 へ移行した

Nuxt 2.4.0 がリリースされたので、会社のWEBサイトで、本番に反映してみた。 ja.nuxtjs.org

やったこと

storeをモジュールモードへ

https://ja.nuxtjs.org/guide/vuex-store/ クラシックモード使ってると、警告が出たので、モジュールモードに変更。

プラグインのファイル名変更

plugins: [
  { src: '~/plugins/plugin.js', ssr: false }
]

を、

plugins: [
  '~/plugins/plugin.client.js'
]

に変更。 ファイル名だけで、SSRの時、読み込まないようにするとかが、分かりやすくなった。

yarn.lock削除して、yarn install

念のため一旦削除

エラったこと

NODE_ENV=production yarn run build 時だけ、file-loader がなくてエラーが起きた。 単に、yarn add file-loader 後に、buildしたらできたけど、前までは必要なかったから原因よくわからないまま。

感想

さらなる速度改善によるUXの改善が見込めそう。 まだ、5時間ぐらいしか本番運用して、経過してないけど、安定して動いてくれてて、毎回コミュニティの方々には感謝しかない。 NuxtとVueのコミュニティの方々に、寄付しないといけないなと思った。

あと、そろそろNuxt Usersに感謝の気持ちを書かないと。 Nuxt Users 💻 · Issue #4681 · nuxt/nuxt.js · GitHub

DockerFileメモ

メモ内容

開発時は、Nuxt + Railsで、本番はnuxt build したものを、RailsのPublicフォルダに渡すみたいなことをする時のDockerFileメモ。 実際使うときは、Nuxtビルドしたものは、S3とかに置くと思うので、使い道はないかもしれないけど...

開発時

Nuxt

FROM node:10.13.0-alpine
ENV LANG C.UTF-8

# Create app directory
RUN mkdir /frontend
WORKDIR /frontend

ADD . /frontend

RUN npm i -g yarn
ADD yarn.lock /frontend/yarn.lock
RUN yarn install

CMD yarn run dev

Rails

FROM ruby:2.5.3-alpine3.8

RUN cd /tmp \
  && apk --no-cache add \
    curl \
    curl-dev \
    libstdc++ \
    libxml2-dev \
    libxslt-dev \
    linux-headers \
    mysql-client \
    mysql-dev \
    postgresql-client \
    postgresql-dev \
    pcre \
    ruby-dev \
    ruby-json \
    tzdata \
    yaml \
    yaml-dev \
    bash \
    build-base \
    zlib-dev

# Rails App
RUN mkdir /app
WORKDIR /app

ADD Gemfile /app/Gemfile
ADD Gemfile.lock /app/Gemfile.lock
RUN bundle install --jobs=4

ADD . /app

RUN mkdir -p tmp/sockets
RUN mkdir -p tmp/pids

# Expose volumes to frontend
VOLUME /app/public
VOLUME /app/tmp
VOLUME /app/log

# Start Server
CMD bundle exec puma -e local

DockerCompose

version: "2"
services:
  app:
    build: .
    image: rails
    volumes:
      - .:/app
    ports:
      - "3000:3000"

  nuxt:
    image: nuxt
    build: frontend
    ports:
      - "4000:4000"
    volumes:
      - .:/frontend
      - node-modules-data:/frontend/node_modules

volumes:
  node-modules-data:

本番

# build
FROM node:10.13.0-alpine AS build-html

# node-sassのためにpython2が必要
RUN apk --no-cache add python

RUN mkdir /fontend
ADD frontend /frontend

WORKDIR /frontend
RUN npm i -g yarn
RUN yarn install
ARG ENV
RUN yarn run build:production

# RUN
FROM ruby:2.5.3-alpine3.8

RUN cd /tmp \
  && apk --no-cache add \
  curl \
  curl-dev \
  libstdc++ \
  libxml2-dev \
  libxslt-dev \
  linux-headers \
  mysql-client \
  mysql-dev \
  postgresql-client \
  postgresql-dev \
  pcre \
  ruby-dev \
  ruby-json \
  tzdata \
  yaml \
  yaml-dev \
  bash \
  build-base \
  zlib-dev

RUN mkdir /app
WORKDIR /app

ADD Gemfile /app/Gemfile
ADD Gemfile.lock /app/Gemfile.lock
RUN bundle install --jobs=4

ADD . /app

RUN mkdir -p tmp/sockets
RUN mkdir -p tmp/pids

# copy build html file
COPY --from=build-html /frontend/public /app/public

# Expose volumes to frontend
VOLUME /app/public
VOLUME /app/tmp
VOLUME /app/log

# Start Server
ARG ENV
CMD bundle exec puma

TwitterAPIで、DMを受け取り、DMを返す

目的

お手伝いしてる案件で、TwitterAPI使ってみたのでメモ APIRailsで実装した。

方法

Twitterの開発用アカウント作って、自分のアプリケーションのURLを登録する。

下のURLがわかりやすいので、参考に。 qiita.com

この通りにやれば、別のTwitterアカウントから、開発しているTwitterアカウントにDirectMessageを送ると、APIが叩かれる。

APIの中身を実装する。

下はRubyで実装してあるので、この通りにすればとりあえず動いた GitHub - twitterdev/SnowBotDev: A demo illustrating the Twitter Account Activity and Direct Message APIs.

quick_reply っていう項目があって、これにデータを入れて、レスポンスを返すと、DMの下に選択肢が出るので、便利だなと思った。

簡単に説明

注) パラメーターはミスしてるかもなので、実際に実装するときは、SnowBotDevのgithub参考にしてください。

DMが送られると、TwitterからAPIに、以下のパラメータでリクエストが届く。

params = {
  direct_message_events: {
    type: 'message_create',
    sender_id: 'DMを送信したユーザーのID'
    message_create: {
      message_data: {
        text: 'hogehoge' // ここに文字が入ってるときは、直接DMが送られたとき。
        quick_reply_response: {
          metadata: 'hogehoge' // ここに文字が入ってるときは、こちらが提示した選択肢を押したとき
        }
      }
    }
  }
} 

このリクエストをみて、下のようなレスポンスを作成する。

{
  event: {
    type: 'message_create',
    target: {
       recipient_id: 'DMを送りたいユーザーのID'
    }
    message_create: {
      message_data: {
        text: 'DM message' // DMで送りたいメッセージを入れる
        quick_reply: {  // ここにデータを入れると選択肢を提示できる。
          options: {
            label: '選択肢に出てくるラベル',
            description: '選択肢の説明',
            metadata: '選択肢のIDみたいなもの。この選択肢を押したとき、quick_reply_responceにこの値が入って、再度イベントが送られる。'
          }
        }
      }
    }
  }
}

このレスポンスを、OAuth認証利用して、TwitterAPIに送る

https://github.com/twitterdev/SnowBotDev/blob/master/app/helpers/api_oauth_request.rb

Nuxt&SSRでsetIntervalを使う時の注意点

ssr.vuejs.org

上記にあるように beforeCreatecreatedsetInerval を使うと、SSR中に呼び出されるので、サーバでsetIntervalが実行されて、clearIntervalをしない限り永遠に続いて行く... 気づかず実装してしまって、焦ったのでメモ。

怖いので、mixins 使ってwrapperしてみた。 考えたこととしては、 - created でなく、mounted を使う - process.server 時に行わないようにする。(mountedの時点で呼ばれないはずだからいらないかも?) - beforeDestory の時あたりで、clearIntervalを行う - 本当は必要ないが、未来の自分が信用できないので、念のため時間設定でclearIntervalを設定しておく。

以下プログラム

export default {
  data() {
    return {
      intervalID: null
    };
  },
  methods: {
    setTimer: function(callback, intervalTime) {
      if (process.server) return;
      this.intervalID = setInterval(() => {
        callback();
      }, intervalTime);

      // 万が一の不具合を防ぐために、ClearIntervalを実施する。(とりあえず30分)
      setTimeout(() => {
        clearInterval(this.intervalID);
      }, 30 * 60 * 1000);
    }
  },
  beforeDestroy() {
    clearInterval(this.intervalID);
  }
};
<script>
  import timer from '~/mixins/utils/timer.js'
  export default {
  mixins: [timer],
  mounted: {
    this.setTimer(this.function, intervalTime);
  }
}
 </script>