#node js app dockerfile
Explore tagged Tumblr posts
Text
Develop & Deploy Nodejs Application in Docker | Nodejs App in Docker Container Explained
Full Video Link https://youtu.be/Bwly_YJvHtQ Hello friends, new #video on #deploying #running #nodejs #application in #docker #container #tutorial for #api #developer #programmers with #examples is published on #codeonedigest #youtube channe
In this video we will learn how to develop nodejs application and deploy it in docker container. I will show do you build nodejs helloworld application and run it in docker container. You will be able to create nodejs helloworld application & run it in docker container in 10 mins. ** Important Nodejs Packages or Modules ** Express – Express is a node js web application framework that…

View On WordPress
#docker#docker image#docker image creation tutorial#docker image node express#docker image nodejs#docker image vs container#docker tutorial#docker tutorial for beginners#dockerize node js express app#learn docker#node js and express js project#node js and express js tutorial#node js app docker#node js app dockerfile#node js application docker file#node js tutorial#node js tutorial for beginners#nodejs#nodejs projects#what is docker
0 notes
Text
Portable Node development environment with Docker
If you read our blog, you could remember our article about Docker explained in details. But there are more and more details appearing every time. Today we would like to share with you a new one. Portable Node development environment with Docker. To run a simple “Hello World!” Node...
#container#container OS#containerization#containers#development environment#docker#Dockerfile#IDE#js#Node#Node applications#Node apps#Node IDE#Node.js#Node.js community#npm#portable#server#web development#Yarn
3 notes
·
View notes
Photo
VuexをTypeScriptで利用するのに悩んだ https://ift.tt/2MOnODr
概要
Vue.jsをTypeScriptで開発する際にVuexを利用するのにしっくりくる実装方法を模索中で、いくつか方法を試してみました。
GitHubに利用したプロジェクトをUPしています。実際に試してみたい方どうぞ^^
https://github.com/kai-kou/vue-js-typescript-vuex
準備
ここではDockerを利用して環境構築していますが、ローカルで構築してもらってもOKです。
> mkdir 任意のディレクトリ > cd 任意のディレクトリ > vi Dockerfile > vi docker-compose.yml
Dockerfile
FROM node:10.8.0-stretch RUN npm install --global @vue/cli WORKDIR /projects
docker-compose.yml
version: '3' services: app: build: . ports: - "8080:8080" volumes: - ".:/projects" tty: true
> docker-compose up -d > docker-compose exec app bash
コンテナ内
> vue create app Vue CLI v3.0.1 ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, TS, Vuex, Linter, Unit ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript for auto-detected polyfills? Yes ? Pick a linter / formatter config: TSLint ? Pick additional lint features: Lint on save ? Pick a unit testing solution: Mocha ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No ? Pick the package manager to use when installing dependencies: (Use arrow keys) ❯ Use Yarn Use NPM
コンテナ内
> cd app > yarn serve
これで実装の準備が整いました。
Vue-Cli標準
vue create コマンドでプロジェクトを作成するとsrc直下にstore.tsが作成されているので、そこに実装をいれて利用するパターンです。
stateにcounter ってのを持っていて、それをインクリメントするアクションがあるだけです。
src/store.ts
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); interface State { conuter: number; } export default new Vuex.Store({ state: { conuter: 0, } as State, getters: { getCounter: (state, getters) => () => { return state.conuter; }, }, mutations: { increment(state, payload) { state.conuter += 1; }, }, actions: { incrementAction(context) { context.commit('increment'); }, }, });
App.vueで使ってみます。 超適当ですが、画像にclickイベント定義して、HelloWorldコンポーネントでstateに定義しているcounter を表示してます。
src/App.vue
<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" @click="increment"> <HelloWorld :msg="`Welcome to Your Vue.js + TypeScript App ${this.counter}`"/> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; import HelloWorld from './components/HelloWorld.vue'; @Component({ components: { HelloWorld, }, }) export default class App extends Vue { private get counter(): number { return this.$store.getters.getCounter(); } private increment(): void { this.$store.dispatch('incrementAction'); } } </script> (略)
ブラウザで確認すると、画像をクリックするとcounterがインクリメントするのが、確認できます。
気になる点
実装はシンプルで良いのですが、規模が大きくなってくると、store.tsが肥大化してくるのが目に見えます。辛い。
this.$store を利用するので、メソッド名などを間違えていても実行時にしかエラーにならないので、せっかくTypeScript使っているのになーです。
src/App.vue
export default class App extends Vue { private get counter(): number { return this.$store.getters.getCounter2(); // 実行時にエラー } private increment(): void { this.$store.dispatch('incrementAction2'); // 実行時にエラー } }
vuex-type-helperを利用する
下記���事で紹介されていたvuex-type-helperを利用してみます。
Vue.js + Vuex + TypeScript を試行錯誤してみた https://logs.utahta.com/blog/2017/09/02/110000
ktsn/vuex-type-helper https://github.com/ktsn/vuex-type-helper
vuex-type-helperとvuex-classってのを追加します。
コンテナ内
> yarn add vuex-type-helper vuex-class
storeの実装を追加します。ここではモジュール化してみます。
> mkdir -pv store2/modules > touch store2/index.ts > touch store2/modules/app.ts
store2/index.ts
import Vue from 'vue'; import Vuex from 'vuex'; import { app } from '@/store2/modules/app'; Vue.use(Vuex); export default new Vuex.Store({ modules: { app, }, });
store2/modules/app.ts
import Vuex, { createNamespacedHelpers } from 'vuex'; import { DefineActions, DefineGetters, DefineMutations } from 'vuex-type-helper'; export interface State { counter: number; } export interface Getters { counter: number; } export interface Mutations { increment: {}; } export interface Actions { incrementAction: {}; } export const state: State = { counter: 0, }; export const getters: DefineGetters<Getters, State> = { counter: (state) => state.counter, }; export const mutations: DefineMutations<Mutations, State> = { increment(state, {}) { state.counter += 1; }, }; export const actions: DefineActions<Actions, State, Mutations, Getters> = { incrementAction({ commit }, payload) { commit('increment', payload); }, }; export const { mapState, mapGetters, mapMutations, mapActions, } = createNamespacedHelpers<State, Getters, Mutations, Actions>('app'); export const app = { namespaced: true, state, getters, mutations, actions, };
利用できるようにmain.tsとApp.vueを編集します。
src/main.ts
import Vue from 'vue'; import App from './App.vue'; -import store from './store'; +import store from './store2';
src/App.vue
import { Component, Vue } from 'vue-property-decorator'; import HelloWorld from './components/HelloWorld.vue'; import { Getter } from 'vuex-class'; import * as app from './store2/modules/app'; @Component({ components: { HelloWorld, }, methods: { ...app.mapActions(['incrementAction']), }, }) export default class App extends Vue { @Getter('app/counter') private counter!: number; private incrementAction!: (payload: {}) => void; private increment(): void { this.incrementAction({}); } } (略)
はい。
気になる点
こちらの利点としてはモジュール化しやすい点と、アクション名を間違えてたときにビルドエラー吐いてくれる点でしょうか。
メソッド名間違い
methods: { ...app.mapActions(['incrementAction2']), },
エラー出してくれる
Argument of type '"incrementAction2"[]' is not assignable to parameter of type '"incrementAction"[]'. Type '"incrementAction2"' is not assignable to type '"incrementAction"'.
getterで間違ってる場合は、ブラウザ側でエラーになります。惜しい。
プロパティ名間違い
@Getter('app/counter2') private counter!: number;
ブラウザでエラー
vuex-classを利用するとActionなんかも以下のような定義ができるけれど、getterと同様にメソッド名間違いがブラウザでしか検知できないので、微妙。
vuex-classでAction定義
@Action('app/incrementAction') private incrementAction!: (payload: {}) => void;
うーん。独自実装いれたらもっとブラウザエラーを回避できそうですが、どこまで実装しようか悩ましいところです。
Vue.js+TypeScriptで開発するときの参考記事まとめ https://qiita.com/kai_kou/items/19b494a41023d84bacc7
元記事こちら
「VuexをTypeScriptで利用するのに悩んだ」
September 20, 2018 at 04:00PM
1 note
·
View note
Link
はじめに 世はエンジニア戦国時代。Dockerくらい一般常識。Docker使えないなんてエンジニアを名乗れない。そんな時代です。(ほんとか?) この記事を書き始めた時の僕のDocker戦闘力は「Docker公式チュートリアルを眺めただけ」です。 なので逆に言えばDocker公式チュートリアルをやっただけの方にも理解できるかと思います。 (ちなみにKubernetes戦闘力は「なんでKubernetesをk8sって言うのかだけ知ってる」です。) この記事はそんな僕が「Docker/Kubernetesちょっと分かる」になるまでにやったことを後から追えるようにズラっと書き連ねたものになります。 使用するのは僕の大好きな言語ElixirとそのWebフレームワークPhoenixです。が、この記事でどの言語を用いているかは重要ではありません。 (記事内でElixirのコードはほぼ触らないですし) また、Railsがわかる方は以下の記事でRailsとPhoenixのコマンドを対応させて説明しているのでチラ見するとPhoenixで何をしようとしているか理解できるかと思います。 Rails経験者に贈るPhoenix入門 何か訂正や補足、アドバイスなどありましたら、是非是非コメントかTwitterまでお願いします!🙇♂️ この記事で扱う内容 Webアプリケーションを扱える環境をDockerfileで作成する docker-composeを使ってWebアプリケーション(+DB)を動かす 作成したimageをdockerhubに上げる Kubernetes(minikube)を使ってWebアプリケーション(+DB)を動かす Dockerfileの作成 では早速Dockerfileを作成していきます Dockerfileではこれから作成するコンテナで何をしようとしているかを定義します。 以下の公式リファレンスが参考になります。 Dockerfile リファレンス Dockerfile FROM elixir:1.10.2 RUN curl -sL https://deb.nodesource.com/setup_12.x | bash RUN apt-get install -y nodejs RUN npm install npm@latest -g RUN mix local.hex --force RUN mix archive.install hex phx_new 1.4.12 --force RUN mix local.rebar --force WORKDIR /app このDockerfileが何をしようとしているか 初心者なりに一行ずつ説明してみます。 親イメージを選択します。 イメージって何?という方は以下の公式チュートリアルの説明がわかりやすいです Part 1:概要説明とセットアップ | コンテナの概要を説明 この親イメージはElixir公式のimageです。 こういった公式で出ているイメージなどから自分の目的に即した環境が作れるようにDockerfileを記述していって、カスタムしていく訳です。 (今回だと自分の目的=Phoenixを動かせる環境となります) RUN curl -sL https://deb.nodesource.com/setup_12.x | bash RUN apt-get install -y nodejs RUN npm install npm@latest -g nodejsが必要なのでインストールしています。 ちなみにはじめはこの部分を以下のように記述していたのですが、(nodejsにnpmは同梱のはず) こうするとその後bash: npm: command not foundが出てしまいます。 以下のページを参考に上のコードに落ち着きました。 Dockerでphpコンテナとかにnpmをインストールするときのメモ RUN apt-get update \ && apt-get install -y nodejs RUN mix local.hex --force RUN mix archive.install hex phx_new 1.4.12 --force RUN mix local.rebar --force hexというElixirのパッケージ管理ツールをインストールします。 (Rubyでいうrubygems) ここで--forceがついてるのは以下のエラーが出るためです Shall I install Hex? (if running non-interactively, use "mix local.hex --force") [Yn] ** (Mix) Could not find an SCM for dependency :phx_new from Mix.Local.Installer.MixProject 途中でyesと答えなければいけない部分があるのですが、それを--forceをつけることで無視してインストールできます。 postgresはどうすんの? はい、先ほどのDockerfileではElixir(Phoenix)の環境しか整っていません。 postgresのコンテナも作らなければいけないです。 しかし - postgresのコンテナとPhoenixのコンテナ間の通信はどうするの? - コンテナ間通信を頑張って設定したとしても毎回それを設定するの? - 毎回postgresのコンテナ、Phoenixのコンテナを両方立てるのめんどくせえ という問題たちが出てきます。 これらを解決してくれるのがdocker-composeです ※ちなみにdocker-composeを使わないコンテナ間通信は以下のページを参考にすればできそうです。 https://kitsune.blog/docker-network#i 「いやいや同じコンテナにDBも突っ込めばええやん!」について そうなるかもですが、コンテナを分けることにはちゃんと理由があります。 この後出てくるdocker-composeとKubernetesではアクセス分散のために複数のコンテナでWebサーバーを動かすことができます。 同じコンテナにDBも一緒に入れてしまうと、この際にDBもたくさんできてしまい、どのコンテナに接続されるかでDBの中身が変わってしまうと言う事態が起こります。 これを防ぐためにDBとWebでコンテナを分けてWebのコンテナを増やしても同じDBを参照するように設定すべきな訳です docker-composeを使用する docker-composeを使用するためにdocker-compose.ymlを作成します。 docker-compose.ymlにはdockerのコンテナ達やネットワークについてあるべき姿を記述します。 するとdocker-composeがそれを元に良しなに設定してくれるわけです。 以下のように作成します。 docker-compose.yml version: "3" #docker-composeのバージョン指定 services: #ここより下でserviceを定義 web: build: . #使用するDockerfileの場所 ports: #portをバインド - '4000:4000' volumes: #hostの./を/appとして共有 - .:/app command: mix phx.server #サーバー起動のためのコマンド depends_on: - db #webの開始前にdbを起動 db: image: postgres #使用するimage environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_HOST=db 以下の公式リファレンスがすごく参考になります。 Compose ファイル・リファレンス docker-compose.ymlに定義したcommandやportsはCMDやEXPOSEとしてDockerfileで定義することもできます。 これでDockerでElixir/Phoenixの環境を使用する準備ができました。 ※volumesに関してはファイルを共有できるという面と、コンテナの外にファイルを安全に置いておけるという面もあります。詳しくはKubernetesの章で出てきます。 適当なサンプルアプリを作ってみる テストもかねてサンプルアプリを作ってみます。(アプリ名はdododoにしました) $ docker-compose run web mix phx.new . --app dododo Creating network "docker-elixir_default" with the default driver Creating docker-elixir_db_1 ... done The directory /app already exists. Are you sure you want to continue? [Yn] y * creating config/config.exs * creating config/dev.exs * creating config/prod.exs * creating config/prod.secret.exs * creating config/test.exs * creating lib/dododo/application.ex * creating lib/dododo.ex * creating lib/dododo_web/channels/user_socket.ex * creating lib/dododo_web/views/error_helpers.ex * creating lib/dododo_web/views/error_view.ex * creating lib/dododo_web/endpoint.ex * creating lib/dododo_web/router.ex * creating lib/dododo_web.ex * creating mix.exs * creating README.md * creating .formatter.exs * creating .gitignore * creating test/support/channel_case.ex * creating test/support/conn_case.ex * creating test/test_helper.exs * creating test/dododo_web/views/error_view_test.exs * creating lib/dododo/repo.ex * creating priv/repo/migrations/.formatter.exs * creating priv/repo/seeds.exs * creating test/support/data_case.ex * creating lib/dododo_web/controllers/page_controller.ex * creating lib/dododo_web/templates/layout/app.html.eex * creating lib/dododo_web/templates/page/index.html.eex * creating lib/dododo_web/views/layout_view.ex * creating lib/dododo_web/views/page_view.ex * creating test/dododo_web/controllers/page_controller_test.exs * creating test/dododo_web/views/layout_view_test.exs * creating test/dododo_web/views/page_view_test.exs * creating lib/dododo_web/gettext.ex * creating priv/gettext/en/LC_MESSAGES/errors.po * creating priv/gettext/errors.pot * creating assets/webpack.config.js * creating assets/.babelrc * creating assets/js/app.js * creating assets/js/socket.js * creating assets/package.json * creating assets/css/app.css * creating assets/static/favicon.ico * creating assets/css/phoenix.css * creating assets/static/images/phoenix.png * creating assets/static/robots.txt Fetch and install dependencies? [Yn] y * running mix deps.get * running cd assets && npm install && node node_modules/webpack/bin/webpack.js --mode development * running mix deps.compile We are almost there! The following steps are missing: $ cd app Then configure your database in config/dev.exs and run: $ mix ecto.create Start your Phoenix app with: $ mix phx.server You can also run your app inside IEx (Interactive Elixir) as: $ iex -S mix phx.server また、しっかりホストとのファイル共有もできていることがわかります。 $ ls Dockerfile _build config docker-compose.yml mix.exs priv README.md assets deps lib mix.lock test config/dev.exsの微修正 config/dev.exsはdev環境の設定ファイルです。 データベースのホスト名をdbに変更しておきます。 config/dev.exs # Configure your database config :dododo, Dododo.Repo, username: "postgres", password: "postgres", database: "dododo_dev", hostname: "db", #fix show_sensitive_data_on_connection_error: true, pool_size: 10 DBの作成 $ docker-compose run web mix ecto.create Starting docker-elixir_db_1 ... done (省略) Generated dododo app The database for Dododo.Repo has been created うまく作成できました。 これでDBとの連携もうまくいっている事がわかります。 サンプルアプリを立ち上げてみる 以下のように表示されれば成功です。 dockerhubにあげる imageを確認してtagをつける $ 507e3f91e80f 55 minutes ago 1.28GB dododo_web latest d7724891c88c 4 hours ago 1.27GB elixir 1.10.2 d6641893fb96 12 hours ago 1.23GB postgres latest 73119b8892f9 2 days ago 314MB $ docker tag a9ff6e7b157f sanposhiho/phoenix:latest dockerhubにログイン $ docker login Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: sanposhiho Password: Login Succeeded 以下のリンクから適当にCreate Repositoryします。 https://hub.docker.com/repository/create 作ったRepositoryにpushします。 $ docker push sanposhiho/phoenix dockerhubにあげると何ができるのか dockerhubにあげる事でDockerfileが必要なくなります。 すなわちdocker-compose.ymlさえあれば先ほどの環境が作成できるわけです。 docker-compose.ymlを修正 Dockerfileを使用しない形にdocker-compose.ymlを修正します。 docker-compose.yml version: "3" services: web: image: sanposhiho/phoenix #先ほど作成したimage ports: - '4000:4000' volumes: - .:/app command: mix phx.server depends_on: - db db: image: postgres environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_HOST=db 変更箇所はwebのimageの部分です。 Dockerfileを参照していたのを先ほど作成したimageを指定しました。 これによりsanposhiho/phoenixをローカルで削除してからdocker-compose upしても $ docker-compose up Creating network "docker-elixir_default" with the default driver Pulling db (postgres:)... latest: Pulling from library/postgres 68ced04f60ab: Pull complete 59f4081d08e6: Pull complete 74fc17f00df0: Pull complete 8e5e30d57895: Pull complete a1fd179b16c6: Pull complete 7496d9eb4150: Pull complete 0328931819fd: Pull complete 8acde85a664a: Pull complete 38e831e7d2d3: Pull complete 582b4ba3b134: Pull complete cbf69ccc1db5: Pull complete 1e1f3255b2e0: Pull complete c1c0cedd64ec: Pull complete 6adde56874ed: Pull complete Digest: sha256:110d3325db02daa6e1541fdd37725fcbecb7d51411229d922562f208c51d35cc Status: Downloaded newer image for postgres:latest Pulling web (sanposhiho/phoenix:)... latest: Pulling from sanposhiho/phoenix 50e431f79093: Already exists dd8c6d374ea5: Already exists c85513200d84: Already exists 55769680e827: Already exists f5e195d50b88: Already exists f7e2598a9cb7: Already exists 9ba52fdf113f: Already exists 896d0883eede: Already exists 019ae449ef4b: Already exists a653e3c2dbc7: Pull complete 1b5116636524: Pull complete 6a7182c301e9: Pull complete ff51ec8f406c: Pull complete 4c53f0b7d33e: Pull complete 79b95deb3b15: Pull complete 4e0c0135d3e7: Pull complete Digest: sha256:ab7dbe3a514597f3e390f90de76de6465defb90103f58c3f08e34db97d890ae7 Status: Downloaded newer image for sanposhiho/phoenix:latest Creating docker-elixir_db_1 ... done Creating docker-elixir_web_1 ... done このようにsanposhiho/phoenixがなくても勝手にdockerhubから取ってきてくれます。 Kubernetesをやっていく 以下の記事を参考に先ほどの環境をKubernetes(minikube)でも動かしてみます。 Docker ComposeからMinikube + Komposeに移行してみよう Komposeと言うのはdocker-compose.ymlをKubernetes向けの設定ファイルに変換してくれる便利なやつです。 そもそもKubernetesって? 色々見ました���以下の記事の前半部分の説明がとても分かり易かったです 数時間で完全理解!わりとゴツいKubernetesハンズオン!! Komposeを使う前に色々修正 Dockerfile Dockerfile FROM elixir:1.10.2 RUN curl -sL https://deb.nodesource.com/setup_12.x | bash RUN apt-get install -y nodejs RUN npm install npm@latest -g RUN mix local.hex --force RUN mix archive.install hex phx_new 1.4.12 --force RUN mix local.rebar --force RUN apt-get install ca-certificates #追加 COPY . /app #追加 WORKDIR /app これを先ほどの手順でdockerhubに上げます (僕はsanposhiho/phoenix_for_k8sとして上げました。) docker-compose.yml docker-compose.yml version: "3" services: web: image: sanposhiho/phoenix_for_k8s #変更 ports: - '4000:4000' command: mix phx.server depends_on: - db db: image: postgres ports: - "5432:5432" #追加 environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_HOST=db 追加/変更の他にvolumeの部分が削除されています。 komposeで変換 $ kompose convert INFO Kubernetes file "db-service.yaml" created INFO Kubernetes file "web-service.yaml" created INFO Kubernetes file "db-deployment.yaml" created INFO Kubernetes file "web-deployment.yaml" created 幾つかのファイルが作成されました。 生成されたファイルを微修正 web-service.yamlに以下を追記します。 web-servise.yaml apiVersion: v1 kind: Service metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: web name: web spec: ports: - name: "4000" port: 4000 targetPort: 4000 selector: io.kompose.service: web type: NodePort #追加 status: loadBalancer: {} これにより外の世界からアクセス可能になります。 生成されたファイルを見ていく Komposeが生成してくれたファイルを見ていきます。 以下の公式ドキュメントが理解の上で役立つと思います。 Kubernetes | Kubernetesオブジェクトを理解する Komposeによって大きく分けて「Deployment」と「Service」の二つが作成されています。 Deploymentとは Deploymentに関しては以下の公式ドキュメントがわかりやすいです。 Kubernetes | Deployment 以下の記事も(少し古いですが)とても参考になりました。 Kubernetes: Deployment の仕組み deploymentはpod(Kubernetesの管理する最小単位)を管理します。 (正確にはpodを管理するReplicaSetを作成します。) 実際に作成されたweb-deployment.yamlを見てみます。 web-deployment.yaml apiVersion: apps/v1 #どのバージョンのKubernetesAPIを利用するか kind: Deployment #何についての定義ファイルか metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: web name: web #deploymentの名前 spec: replicas: 1 #replicaの数 selector: matchLabels: io.kompose.service: web #podのラベル定義 strategy: {} template: #deploymentが管理するpodの定義 metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: web spec: containers: - args: - mix - phx.server image: sanposhiho/phoenix_for_k8s imagePullPolicy: "" name: web ports: - containerPort: 4000 resources: {} restartPolicy: Always serviceAccountName: "" volumes: null status: {} web-deployment.yamlではspec.templateで指定されたpodを常に1つ維持するようにしています。 Serviceとは 以下の公式ドキュメントが参考になります。 Kubernetes | Service PodはそれぞれがIPアドレスを持っています。例えば今回のようにDBのPodとWebサーバーのPodに別れている場合、WebサーバーがDBのPodにアクセスするにはDBのPodのIPアドレスが必要になります。 そこでServiceはpodたちをセットで管理し(「DBのPod」「サーバーのPod」と言う風に管理)、そのセットに対してのアクセスが可能になります。 例えPodが動的に入れ替わったりしても一貫した方法でのアクセスが可能になります。 (Service無しだと、何かの障害で一つのPodが死んで、Deploymentが代わりのPodに入れ替えた時にはIPアドレスが変わってしまうのでアクセスができなくなってしまいます) 実際に作成されたweb-service.yamlをみてみます。 web-service.yaml apiVersion: v1 kind: Service metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: web name: web spec: ports: #管理するportに関して - name: "4000" port: 4000 targetPort: 4000 selector: #管理するPodの指定 io.kompose.service: web type: NodePort status: loadBalancer: {} 先ほど追加したtype: NodePortは指定しなかった場合デフォルト値としてClusterIPに指定されます。 ClusterIP: クラスター内部のIPでServiceを公開する。このタイプではServiceはクラスター内部からのみ疎通性があります。 これではクラスターの外部からのアクセスができなかったためNodePortに変更しました NodePort: 各NodeのIPにて、静的なポート(NodePort)上でServiceを公開します。そのNodePort のServiceが転送する先のClusterIP Serviceが自動的に作成されます。:にアクセスすることによってNodePort Serviceにアクセスできるようになります。 Serviceの公開 (Serviceのタイプ) minikubeを立ち上げておく ダッシュボードを開いておく ダッシュボードを使えば以下のようにPodなどの状態をブラウザから確認できます。 立ち上げ! ついにKubernetes上で立ち上げてみます。 $ kubectl apply -f db-deployment.yaml $ kubectl apply -f web-deployment.yaml $ kubectl apply -f db-service.yaml $ kubectl apply -f web-service.yaml これによってファイルに定義されたもの達が立ち上がります。 kensei-mba:docker-elixir nakatakensei$ kubectl get all NAME READY STATUS RESTARTS AGE pod/db-5fbcf655cd-2k7lw 1/1 Running 0 159m pod/web-87795996-r6rcf 1/1 Running 0 159m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) 4000:30249/TCP 159m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/db 1/1 1 1 159m deployment.apps/web 1/1 1 1 159m NAME DESIRED CURRENT READY AGE replicaset.apps/db-5fbcf655cd 1 1 1 159m replicaset.apps/web-87795996 1 1 1 159m DBを作成する kubectl exec -it web-87795996-r6rcf mix ecto.create で任意のコードをPodに対して実行させることができます。 また、このコードが通る=Serviceが機能してDBに繋いでくれていることを意味します。 ちゃんと立ち上がっているか確認 $ minikube service list |----------------------|---------------------------|--------------|---------------------------| | NAMESPACE | NAME | TARGET PORT | URL | |----------------------|---------------------------|--------------|---------------------------| | default | db | No node port | | default | kubernetes | No node port | | default | web | | http://192.168.64.2:32566 | | kube-system | kube-dns | No node port | | kubernetes-dashboard | dashboard-metrics-scraper | No node port | | kubernetes-dashboard | kubernetes-dashboard | No node port | |----------------------|---------------------------|--------------|---------------------------| webのURLにアクセスします このようにPhoenixのTop画面が表示されれば成功です! これでも動いてはいますが… 現状の設定ではDBのPod内のみにDBのデータが存在します。 なのでDBのPodが死んだ時に全てのデータが死んでしまいます。 一回実験してみましょう ダッシュボードから作成されているKubernetes以外のService, Pod, deploymentを全て削除してください。 以下のようになれば合っています。 WebアプリケーションをDBを使うアプリケーションに作り直す PhoenixにもRailsと同様に便利なgeneratorの機能が搭載されています。 ローカルでgeneratorを使用します。 $ mix phx.gen.html Blog Post posts title:string content:string * creating lib/dododo_web/controllers/post_controller.ex * creating lib/dododo_web/templates/post/edit.html.eex * creating lib/dododo_web/templates/post/form.html.eex * creating lib/dododo_web/templates/post/index.html.eex * creating lib/dododo_web/templates/post/new.html.eex * creating lib/dododo_web/templates/post/show.html.eex * creating lib/dododo_web/views/post_view.ex * creating test/dododo_web/controllers/post_controller_test.exs * creating lib/dododo/blog/post.ex * creating priv/repo/migrations/20200308110013_create_posts.exs * creating lib/dododo/blog.ex * injecting lib/dododo/blog.ex * creating test/dododo/blog_test.exs * injecting test/dododo/blog_test.exs Add the resource to your browser scope in lib/dododo_web/router.ex: resources "/posts", PostController Remember to update your repository by running migrations: $ mix ecto.migrate 書かれているようにrouter.exにルーティングを追加しておきます。 lib/dododo_web/router.ex defmodule DododoWeb.Router do use DododoWeb, :router pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers end pipeline :api do plug :accepts, ["json"] end scope "/", DododoWeb do pipe_through :browser get "/", PageController, :index resources "/posts", PostController #追加 end # Other scopes may use custom stacks. # scope "/api", DododoWeb do # pipe_through :api # end end migrationします $ mix ecto.migrate 11:23:37.327 [info] == Running 20200308110013 Dododo.Repo.Migrations.CreatePosts.change/0 forward 11:23:37.335 [info] create table posts 11:23:37.392 [info] == Migrated 20200308110013 in 0.0s これで/postsにアクセスすると以下のようなアプリが作成できています (画像はNew Postから新たなpostを作成した後です) この変更をdockerhubのimageに反映させます。 先ほど説明した手順とほとんど同じなのでコマンドだけ載せておきます。 $ docker build . $ docker images #image idを取得 $ docker tag <image id sanposhiho/phoenix_for_k8s $ docker push sanposhiho/phoenix_for_k8s minikube環境で変更後のアプリケーションを動かす こちらもほぼ手順が変わらないのでコマンドだけ載せておきます。 $ kubectl apply -f db-deployment.yaml $ kubectl apply -f web-deployment.yaml $ kubectl apply -f db-service.yaml $ kubectl apply -f web-service.yaml $ kubectl get pods #pod nameの確認 $ kubectl exec -it mix ecto.create $ kubectl exec -it mix ecto.migrate 先ほどと違うのは最後に mix ecto.migrateが追加されていることです。これによってpostsテーブルがDBのPod内に作成されます。 画像使い回しですが、以下のページが/postsから確認できれば成功です。 (画像はまたもやNew Postから新たなpostを作成した後です) DBのPodを削除してみる ダッシュボードからDBのPodを削除します。 Deploymentによってすぐに新しいDB用のPodが作られます。(さすが) さて、先ほどのページを開き直してみるとどうなっているでしょうか 訳のわからんエラーが出ています。 「何回かDBにアクセスしようとしたけど、無理でしたー」というエラーです。 無事に(?)DBがPodが死んだことで消えてしまったことがわかりました。 ちなみに以下のコマンドでDBを作り直してPostsテーブルを再作成すると先ほどの「ほげほげ」のデータは残っていませんが、ページが正常に表示されます。 (作り直されたDBのPodに新しく出来たDBだから当たり前ですね) $ kubectl get pods #pod nameの確認 $ kubectl exec -it mix ecto.create $ kubectl exec -it mix ecto.migrate volumeを設定してDBの揮発を防ぐ 長々実験しましたが、このDBの揮発(=永続の逆。Podが死ぬとDBも一緒に消えてしまうと言う意)を防ぐにはvolumeを設定する必要があります。 volumeの設定方法ですが二つ存在しました。 (どっちがいいのかは分からないです…どなたか教えてください。) db-development.yamlのvolumesのみを弄る PersistentVolumeClaimを利用する 1. db-development.yamlのvolumesのみを弄る db-development.yaml apiVersion: apps/v1 kind: Deployment metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db name: db spec: replicas: 1 selector: matchLabels: io.kompose.service: db strategy: {} template: metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db spec: containers: - env: - name: POSTGRES_HOST value: db - name: POSTGRES_PASSWORD value: postgres - name: POSTGRES_USER value: postgres image: postgres imagePullPolicy: "" name: db ports: - containerPort: 5432 volumeMounts: #追加 - mountPath: "/var/lib/postgresql/data" name: pgdata resources: {} restartPolicy: Always serviceAccountName: "" volumes: #追加 - name: pgdata hostPath: path: /Users/nakatakensei/docker-elixir/ #postgresのdataをhostのどこに置いておくか 2. PersistentVolumeClaimを利用する pvc-phoenix.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pv-claim spec: storageClassName: standard accessModes: - ReadWriteOnce resources: requests: storage: 1Gi db-development.yaml apiVersion: apps/v1 kind: Deployment metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db name: db spec: replicas: 1 selector: matchLabels: io.kompose.service: db strategy: {} template: metadata: annotations: kompose.cmd: kompose convert kompose.version: 1.21.0 () creationTimestamp: null labels: io.kompose.service: db spec: containers: - env: - name: POSTGRES_HOST value: db - name: POSTGRES_PASSWORD value: postgres - name: POSTGRES_USER value: postgres image: postgres imagePullPolicy: "" name: db ports: - containerPort: 5432 volumeMounts: - mountPath: "/var/lib/postgresql/data" name: pgdata resources: {} restartPolicy: Always serviceAccountName: "" volumes: - name: pgdata persistentVolumeClaim: #1とはここが違う claimName: pv-claim 先ほどの手順で実験してもらうとどちらの方法を用いてもDB揮発しちゃう問題が解決したことがわかります。 (スクショを撮っても分かり難かったため、ここまで実際に手を動かして進めていただいた方は自分で実験してみてください) 終わりに 最終的なファイル達は以下のリポジトリに上がっています。 https://github.com/sanposhiho/docker-elixir-phoenix すごく長い記事になってしまいました。 しかし、個人的にDocker→Kubernetesと一緒の流れで学べるようなチュートリアルが無かったため記事を分けずにこのように進めました。 どなたかの役に立てば幸いです。 余談 ちなみに、この記事を読んでElixir/Phoenix勉強してみようかなって方がいましたら、この記事を元にDocker環境を立ててもいいですし、ローカルにElixir/Phoenixの環境を整えるには以下の記事が参考になるかと思います。 【2020/02最新】新品のMacBookでElixir(Phoenix)の環境を0から構築する 参考 記事内であげなかったけどチラチラ見て参考にさせていただいたサイトです。 DockerでRuby on Railsの開発をしよう kubernetesクラスタでRailsアプリを公開するチュートリアル Kubernetesの永続化 [PersistentVolume/PersistentVolumeClaim]
0 notes
Photo

p5.js 1.0, Node best practices, and a podcast for the weekend
#478 — March 6, 2020
Unsubscribe : Read on the Web
JavaScript Weekly

An Interactive Introduction to D3 — D3, the JavaScript library for producing interactive data visualizations, has just turned 9 years old so you’re probably familiar with it by now.. but this introduction is particularly neat as it’s an example of a live, interactive ‘notebook’ style tutorial.
MIT Visualization Group
Understanding the ECMAScript Spec, Part 2 — Part 1 looked at how to understand a single (and simple) method by reading the official ECMAScript specs. Part 2 goes into a trickier domain, understanding how ES interpreters do prototype lookups.
Marja Hölttä
🐋 Learn Docker in the New, 'Complete Intro to Containers' — Learn to create containers from scratch and with Dockerfiles, run containers from Docker Hub, and learn best practices are for front-end and Node.js code in containers.
Frontend Masters sponsor
p5.js 1.0: The 'Creative Coding' Libary — A major milestone for a long-standing JavaScript library that builds upon Processing, a popular creative coding environment (which also inspired the Arduino IDE). p5 is a bit hard to explain succinctly, so definitely check it out.
lauren mccarthy
Rollup 2.0 Released: The ES Module Bundler — Write your code using ES modules and get tree-shaking/dead code elimination and bundling to the format you require. v2 gets rid of lots of deprecated stuff, goes zero-dependency, and includes chokidar to improve its ‘watch’ mode’.
Lukas Taegert-Atkinson
A Growing Collection of 86 Node.js Best Practices — An in-depth guide for Node devs, available in multiple languages. Divided into 7 sections and updated regularly.
Yoni Goldberg
💻 Jobs
Senior JavaScript Developer (Warsaw, Relocation Package) — Open source project used by millions of users around the world. Strong focus on code quality. Join us.
CKEditor
JavaScript Developer at X-Team (Remote) — Work with the world's leading brands, from anywhere. Travel the world while being part of the most energizing community of developers.
X-Team
Find a Dev Job Through Vettery — Vettery is completely free for job seekers. Make a profile, name your salary, and connect with hiring managers from top employers.
Vettery
ℹ️ If you're interested in running a job listing in JavaScript Weekly, there's more info here.
📘 Articles & Tutorials
4 Best Practices To Writing Quality ES Modules — Principally these ideas are around organizing modules you create: prefer named exports, do no work during import, favor high cohesion and avoid long relative paths.
Dmitri Pavlutin
The Perils of Rehydration: An Eye-Opening Realization about Gatsby and React — We love how the author explains this piece himself: “Last week, I learned a whole lot about how React’s rehydration works. Wrote up those findings in a blog post!”
Josh W Comeau
Top GitHub Best Practices for Developers — Expanded Guide — Implementing these best practices could save you time, improve code maintainability, and prevent security risks.
Datree sponsor
7 Types of Native Errors in JavaScript You Should Know — A beginner’s level introduction to understanding the meaning behind errors like RangeError, ReferenceError and URIError.
Chidume Nnamdi
▶ Discussing JavaScript Deployments with Brian LeRoux — Brian is well known as an expert in the JavaScript space and is working on a serverless based platform for deploying JavaScript-powered APIs so it’s neat to hear what he thinks.
Software Engineering Daily podcast
▶ Building an Animated Counter with JavaScript — JavaScript has just gotten so serious nowadays, so I like to frequently link to tutorials like this that cover building neat Web page effects.. like we used JavaScript for back in the 90s 😄 18 minutes.
Traversy Media
3 Ways to Render Large Lists in Angular — An overview of the available techniques to render large lists of items with Angular.
Giancarlo Buomprisco
CES, Viacom & Intel Use .Tech Domains. What About You? Search Now
.TECH domains sponsor
In Favor of Small Modules and Plumbing — “This post examines how I used to be of the mindset that publishing a plethora of “focused” modules is a waste of time but now think is a fantastic idea.”
Paul Anthony Webb
An Introduction to Vue.js Computed Properties and Watchers
John Au-Yeung
🔧 Code & Tools

Stryker: Test Your Tests with Mutation Testing — Stryker fiddles with your tests (in a large and complicated number of ways) and expects this to break them. If it doesn’t, your tests are too brittle and therefore failed the test. This is not something to run frequently (as it can be very slow) but is an interesting way to stress test your tests, if you will.
Jansen, de Lang, et al.
Immer 6.0: The Popular Immutable State Library — Immer only continues to get better over time but take note of the breaking changes.
immer
A Much Faster Way to Debug Code Than with Breakpoints or console.log — Move forward and backwards through your code to understand the conditions that led to a specific bug, view runtime values, edit-and-continue, and more.
Wallaby.JS sponsor
Vue Formulate: The Easy Way to Build Forms with Vue.js — A well presented library that brings a lot of simple form-building power to Vue apps.
Braid LLC
Goxygen: Quickly Generate a Go and MongoDB-Backend for a JS Project — We first linked this opinionated full stack app generator only a few weeks ago, but since then it’s had a 0.2 version that extends its support from React to Angular and Vue.js too.
Sasha Shpota
ls-lint: A Fast File and Directory Name Linter — Written in Go but clearly aimed at JS/front-end dev use cases. ls-lint provides a way to enforce rules for file naming and directory structures.
Lucas Löffel
isomorphic-git 1.0: It's git but in Pure JavaScript — A pure JavaScript implementation of git for both Node and the browser.
isomorphic git team
Bootstrap Treeview: A Simple Plugin to Build A Treeview with Bootstrap 4 — Here’s a live demo.
Sami Chniter
🎧 Something for the weekend..
▶ 'Somebody Somewhere Is Generating JS From Fortran..' — This is more a fun podcast listen for the weekend if you have the time. Brian Leroux (yes, again!) and Kevin Ball tackle all sorts of JavaScript topics from modules and progressive bundling to building infrastructure as code and the future of ‘JAMstack’.
JS Party Podcast podcast
by via JavaScript Weekly https://ift.tt/38r0p5L
0 notes
Text
Datadog と Lighthouse を利用した WebPerf の継続的計測
こんにちは。ものづくり推進部、フロントエンドエンジニアの武田です。 今日は Datadog, Lighthouse を使ったクライアントパフォーマンス計測に取り組んでいる、というお話です。
mediba では webpagetest を使った定期実行と計測を以前から行っています。
DataStudioとGASでWebPagetestの計測結果をグラフ化する
uknmr/gas-webpagetest
紹介記事: gas-webpagetestでWebPagetestのパフォーマンス計測を自動化、可視化する
1 での取り組みをベースにし、clasp で GAS のソースコード管理・デプロイを実現するための仕組みや webpagetest Lighthouse test と連携したメトリクスの取得まで網羅したものが 2 になります。
今回は少し webpagetest とは趣向を変えて
Lighthouse による定期実行とパフォーマンス値取得
Datadog API を利用したカスタムメトリクスへの POST
Datadog による可視化
についてご紹介します。
実施に必要なもの
Datadog (Pro Plan or Enterprise Plan での契約)
Node.js v10.13 以上(現時点)、Chrome がインストールされている実行環境
Lighthouse
定期実行する仕組み
超簡単な説明ですが
Datadog とは? -> システム監視のための SaaS
Lighthouse とは? -> クライアントパフォーマンスのスコアリングツール
です。
Lighthouse による定期実行とパフォーマンス値取得
webpagetest ではなくなぜ Lighthouse なのか
webpagetest を利用する場合、自前のプライベートインスタンスとして立てることも可能ですが、コストとの兼ね合いでパブリックインスタンスとして存在するリージョンを利用するというシーンがどうしてもあります。今回はプロダクション環境とパブリックに閲覧が不可能であるステージング環境の2環境を施策に合わせて比較をする必要があるため、どうしてもその制限をクリアできません。
ステージング環境を正常に閲覧できる(=リクエストを受け付けられる)
Lighthouse 実行のために必要な Node.js v10 以上が動作する
Lighthouse 実行のために Chrome が動作する
これらを定期的に実行する
以上を実現することが必要そうです。
どこで Lighthouse 定期的に動かすか
ランタイムを Node.js v10.x にした lambda もしくは CodeBuild でスクリプトを実行、定期スケジューリングを CloudWatch Events にするということも可能そうです。一度 CodeBuild 想定でコストを計算してみます。CodeBuild の OS image は Chrome も素で入っていますし、割となんでも入り感があります。
料金 - AWS CodeBuild | AWS
毎月かかりそうな試算の条件
デイリーで24回実行想定
ビルドにかかる時間 5 分
インスタンスタイプに一番高いクラス 1分単位で 0.02 USD
24回/day * 30day * 5 分 * 0.02 USD = 72 USD
現時点レートで 7,827 円、自分が毎月もらっているお小遣いから出せるかと言われると出せない金額なので今回は AWS 環境での実行を諦めます。
いろいろ考えた結果、ほぼゼロコストで仕上げるため選択したのは Travis CI でした。といっても弊社では Travis CI Enterprise を AWS 環境上で動作させており、そこで実行させる想定です(なので詳細を詰められるとゼロコストではないのですが)。
ただ残念ながら定期実行を叶える Travis Cron Jobs はリポジトリのブランチ毎にマニュアルで指定する必要があるのでそこは残念な感じになります、人間がポチポチ GUI から指定して定期実行を実現することにします。
Lighthouse スクリプト
フロントエンドエンジニアの方ですと Chrome Devtools -> audit や Lighthouse を CLI から利用することは一度はやってみたことがあると思うのですが、今回はよく見るスコアがほしいわけではなく特定のパフォーマンスメトリクスを取得したいという意図です。個人的にも絶対的なスコアリングが全てだと思っていません、計測し比較し向上しているかが一番重要であると思っています。
プログラマブルに Ligththouse を操作していきますが、実はほとんどドキュメントにあったりするので、参考に取得してパフォーマンス値をかき集めてみます。
const lighthouse = require('lighthouse'); const log = require('lighthouse-logger'); const chromeLauncher = require('chrome-launcher'); const opts = { chromeFlags: ["--headless", "--disable-gpu"], logLevel: "info" }; log.setLevel(opts.logLevel); launchChromeAndRunLighthouse("https://stg.example.com", opts).then(results => { // 一旦標準出力に表示 console.table(results); }); function launchChromeAndRunLighthouse(url, opts, config = null) { return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => { opts.port = chrome.port; return lighthouse(url, opts, config).then(results => { // results.lhr はよく見るスコアリングの元データ // https://github.com/GoogleChrome/lighthouse/blob/master/types/lhr.d.ts const { "time-to-first-byte": ttfb, "first-contentful-paint": fcp, "first-meaningful-paint": fmp, "speed-index": speedindex, interactive, metrics, } = results.lhr.audits; return chrome.kill().then(() =>({ TTFB: Math.round(ttfb.numericValue), FIRST_PAINT: metrics.details.items[0].observedFirstPaint, FMP: Math.round(fmp.numericValue), FCP: Math.round(fcp.numericValue), SPEED_INDEX: Math.round(speedindex.numericValue), TTI: Math.round(interactive.numericValue), })); }); }); }
Lighthouse 実行時の Promise.resolve で返却される results は型定義もあり、昨今のエディタ補完の恩恵を受けると大変 DX が良いのですが、必要な数値は正直どこに格納されているか探すほかないので、CLI で一度 JSON ファイルを成果物として実行してから探すのが一番手っ取り早いです。切り取られたスクリーンショットの情報が Base64 でエンコードされ格納されているので違った工夫もできそうではあります。
ここまでで Lighthouse 側の準備は整ったので次に Datadog 側を準備します。
Datadog API を利用したカスタムメトリクスへの POST
そもそもなぜ Datadog を選ぶのか
担当するプロダクトのシステムモニタリングとして現在利用しており(他のプロジェクトでの利用実績もあります)、インテグレーションや API 連携について学びたいというのと、値のプロットと可視化を Datadog 一括にしちゃえば便利だし見るところ少なくていいんじゃね? というのが大きなモチベーションです。
私が活動するメインフィールドはフロントエンドなのですが、チームでは属人化を避けるため監視やアラート対応・調査を含め、モブを通して暗黙知をなくそうという取り組みをしている点も Datadog を候補にした理由です。
Datadog API とカスタムメトリクスの利用
次はDatadog API を使ってカスタムメトリクスを作り POST しますが、まずは API key, APP key が必要になってきます。
ナビゲーションから Intergrations -> APIs
API key, APP key 取得
実際にリクエストを送る際は node-dogapi というのがあるのでこちらを利用してみます。
初期化
const datadog = require("dogapi"); // 環境変数に Datadog API key, Datadog App key がセットされている想定 datadog.initialize({ api_key: process.env.DATADOG_API_KEY, app_key: process.env.DATADOG_APP_KEY, });
カスタムメトリクスへの送信
任意の文字列をカスタムメトリクス名として、収集した値をプロットしていきます。なお以下のコードは先ほど出力に結果を表示したブロックで利用する想定です。タグ名に関しては特定の要素に紐づけ絞り込みを目的として利用を推奨しているようで、公式にもある通りプロダクション環境やステージング環境の種別としてタギングします。タグのルールとしては <KEY>:<VALUE> というルールになります。参照
const { TTFB, FIRST_PAINT, FMP, FCP, SPEED_INDEX, TTI, } = results; const tags = "env:staging"; datadog.metric.send_all([ { metric: "webperf.measure.ttfb", points: TTFB, tags, }, { metric: "webperf.measure.first_paint", points: FIRST_PAINT, tags, }, { metric: "webperf.measure.fmp", points: FMP, tags, }, { metric: "webperf.measure.fcp", points: FCP, tags, }, { metric: "webperf.measure.speed_index", points: SPEED_INDEX, tags, }, { metric: "webperf.measure.tti", points: TTI, tags, }, ], (err, results) => { if (err) { console.log(`Error: ${JSON.stringify()}`); process.exit(1); } console.log(`Results: ${JSON.stringify(results, null, 4)}`); });
ここまでのもの実行できれば Datadog のカスタムメトリクスに値がプロットされ可視化するデータは出来たことになります。
Datadog による可視化
ダッシュボードを作成
新しいダッシュボードを作成しグラフを作る準備をします。
Timeborad: 時系列にイベントグラフを閲覧しレイアウトが自動
Screenboard: ステータスやグラフなどデータとして混合されたもの向けでレイアウトがフレキシブル
2つから選べますがお好きな方を選んで調整してください。
ダッシュボードにウィジェットを追加
グラフで可視化する場合は Timeseries というウィジェットを使用します。
ウィジェットでハマるとしたらタグでの絞り込みな気がします。もしタグがサジェストされないなどうまくいかないようでしたら </> アイコンを押下して raw text での変更に切り替えると avg:webperf.measure.ttfb{key:value} のような入力が可能になるので試してみると良いかもしれません。
最近よく聞くようなパフォーマンスバジェットを閾値として定めて、閾値よりオーバーしたら Warning 表示にする、なおかつ閾値を超えた際にモニタリングによって Slack に通知するといったことも可能です。
Google Developers Japan: パフォーマンスバジェットのご紹介 - ウェブパフォーマンスのための予算管理
ダッシュボードは今のところシンプルですがこんな感じになっています。
日々プロットしたグラフを可視化し追いかけたい数値と、重要視したい値・バジェットを定めてデカデカと表示する、見栄えはよくありませんが実務に事足りるものになっています。
まとめ
Lighthouse から特定の値を取得、Datadog API を使ったカスタムメトリクスへの POST、Datadog 内での可視化について書かせていただきました。
Datadog のカスタムメトリクス利用は Pro/Enterprise プランのみ
手早く低コストで定期実行したいなら CI のサービス利用を検討
Lighthouse の実行結果からはパフォーマンス値やその他(スクショなど)も取得できる
Datadog API の利用は簡単(各種言語のライブラリ等も揃っており充実)
ダッシュボードも気軽で簡単に可視化できる
今回は Datadog のプラン次第というところもありますが、まずは低コストでパフォーマンス定期計測やパフォーマンスバジェットの設定などに取り組んでみてはいかがでしょうか。
0 notes
Video
youtube
Develop Nodejs Application | Run Nodejs Application in Docker Container Full Video Link https://youtu.be/Bwly_YJvHtQ Hello friends, new #video on #deploying #running #nodejs #application in #docker #container #tutorial for #api #developer #programmers with #examples is published on #codeonedigest #youtube channel. @java #java #aws #awscloud @awscloud @AWSCloudIndia #salesforce #Cloud #CloudComputing @YouTube #youtube #azure #msazure #docker #dockertutorial #nodejs #learndocker #whatisdocker #nodejsandexpressjstutorial #nodejstutorial #nodejsandexpressjsproject #nodejsprojects #nodejstutorialforbeginners #nodejsappdockerfile #dockerizenodejsexpressapp #nodejsappdocker #nodejsapplicationdockerfile #dockertutorialforbeginners #dockerimage #dockerimagecreationtutorial #dockerimagevscontainer #dockerimagenodejs #dockerimagenodeexpress #dockerimagenode_modules
#youtube#nodejs#node js training#node js application#node js app docker#docker#docker container#nodejs application in docker container#deploy nodejs application in docker#dockerfile#docker image#create nodejs docker image
1 note
·
View note
Text
Writing Dockerfiles for Node.js Web Apps
https://blog.hasura.io/an-exhaustive-guide-to-writing-dockerfiles-for-node-js-web-apps-bbee6bd2f3c4 Comments
0 notes
Text
Making a React application container environment-aware at Kubernetes deployment
Motivation
This blog is based on the use case of a React web application that is supposed to be deployed to a Kubernetes cluster. To give more context and a better introduction to the problem to be solved, a few practical business logic and infrastructure assumptions will be made. First, the business logic requirement is that this application is available in different variants based on country and product brand. Content will be conditionally rendered depending on these variables. Additionally, the Kubernetes cluster defines multiple environments and passes environment variables for brand and country to a container at runtime through deployment files as follows:
apiVersion: "extensions/v1beta1" kind: "Deployment" metadata: labels: app.kubernetes.io/name: "react-app-test-marke—de" app.kubernetes.io/instance: "react-app-test-marke—de" app.kubernetes.io/version: "$VERSION" name: "react-app-test-marke—de" spec: replicas: 2 ... template: metadata: labels: app.kubernetes.io/name: "react-app-test-marke—de" app.kubernetes.io/instance: "react-app-test-marke—de" spec: containers: - name: "react-app-test-marke—de" image: "${IMAGE}:${VERSION}" env: - name: "BRAND" value: "Test-Marke" - name: "COUNTRY" value: "DE" ...
The same format of deployment yaml file is also applicable to other environments, with BRAND/COUNTRY variants like “Another-Test-Brand”/”UK”, “Test-Marchio”/”IT”.
Of course, this React application should be packaged within a Docker container. Once this container is built, it should be ready to accept environment variables passed from Kubernetes at runtime and apply it to the React app accordingly. The problem is that npm produces static files that do not know anything about variables Kubernetes passes at runtime. So environment variables need to be injected in some other way at runtime.
Possible (but not optimal) approach
The alternative approach to these requirements would be to build each variant separately with environment variables passed to Docker at build phase and then deploy each container to the appropriate environment. This seems like a legitimate approach as npm is able to accept environment variables at npm run build and inject them into the React application, and they can be accessed within the process.env object in React. Still, the obvious problem with this approach is an overuse of build resources, because the same application will be built multiple times with just environment variables being different. Also, it would require quite some CI/CD pipeline infrastructure changes and reorganisation.
A better approach
As already mentioned, the static files (html, js, css, images…) npm produces during the build phase are meant to be final, ready for serving. Still, there is a slight chance to make them more dynamic and inject environment-specific configuration right before serving. To achieve this, the React app needs a configuration file which will contain runtime environment variables. A good place for storing environment variables would be the JavaScript window object as it is application-scope available. Here is an example of such a configuration file:
window.REACT_APP_BRAND=undefined; window.REACT_APP_COUNTRY=undefined;
At first, these variables are assigned with undefined values to serve as placeholders. These values will be overwritten at runtime with injected values. This file should be located in the public folder of the React app. Then npm will pick it up and package it with static files produced during the build. The next step would be to refer this file in the index.html to make it available at application loading. So, in the index.html the following line is added:
...
...
The next step would be the automation of replacing variables placeholders with provided environment values. The natural approach for this would be to create a shell script which will be executed on running a Docker container. Here is a script example (named generate_config_js.sh):
#!/bin/sh -eu if [ -z "${BRAND:-}" ]; then BRAND_JSON=undefined else BRAND_JSON=$(jq -n --arg brand '$BRAND' '$brand') fi if [ -z "${COUNTRY:-}" ]; then COUNTRY_JSON=undefined else COUNTRY_JSON=$(jq -n --arg country '$COUNTRY' '$country') fi cat <
What this script does is check the existence of BRAND and COUNTRY variables passed from the invoking process (which is Docker run in this case) and then appending those variables to the window object. At this point these variables have no connection to the config.js file yet, so it is needed to write output of the script into the config.js file. This can be achieved using following command:
generate_config_js.sh > /usr/share/nginx/html/config.js
After environment variables are injected into the config.js file, static files are ready to be served in the nginx server. Starting the nginx server can be chained with previous command in a separate script like this (named docker-entrypoint.sh):
#!/bin/sh -eu ./generate_config_js.sh >/usr/share/nginx/html/config.js nginx -g "daemon off;"
This last command is very convenient to serve as an entry point for the Docker container run.
This is actually a key point in this blog – these scripts are set in a Docker container during the container build but they are not executed immediately. Cleverly, these scripts will be executed when the Docker container runs within Kubernetes with provided variables. This is what creates an opportunity to manipulate static files right before serving.
Docker container
Finally, the Dockerfile should look like this:
FROM node:9.6.1 as builder RUN mkdir /usr/src/app WORKDIR /usr/src/app ENV PATH /usr/src/app/node_modules/.bin:$PATH COPY package*.json ./ RUN npm install --silent RUN npm install [email protected] -g --silent COPY . /usr/src/app RUN npm run build FROM nginx:1.14.1-alpine RUN apk add --no-cache jq RUN rm -rf /etc/nginx/conf.d COPY conf /etc/nginx COPY --from=builder /usr/src/app/build /usr/share/nginx/html COPY docker-entrypoint.sh generate_config_js.sh / RUN chmod +x docker-entrypoint.sh generate_config_js.sh ENTRYPOINT ["/docker-entrypoint.sh"]
What this Dockerfile does is the following: It uses multistage build to achieve both build and serving within the same container.
It starts from a Node base image and builds React applications the usual way. Then, it takes the nginx base image for serving purposes and copies built static files to a new image, while the previous intermediate image is removed and the image size is reduced.
Finally, it copies shell scripts, attaches execution permissions and exposes the entry point command. To build the Docker container with the previous configuration, as usual, run:
docker build -t sample-container .
To try out this configuration locally, the following command can be run:
docker run -it -e BRAND=Test-Brand -e COUNTRY=DE -p 80:80 --rm sample-container:latest
This command will simulate how the Docker container will actually be run by Kubernetes. If everything went well, there should be a React application running on http://localhost (port 80). In the browser inspector (for example, Google Chrome Dev Tools) there should be a config.js file rewritten with variable values passed from Kubernetes deployment:
window.REACT_APP_BRAND='Test-Brand'; window.REACT_APP_COUNTRY='DE';
Accessing environment variables in React code is done through the window object:
... switch (window.REACT_APP_COUNTRY
){ case 'DE': return GermanHeaderComponent; case 'UK': return EnglishHeaderComponent; case 'IT': return ItalianHeaderComponent; default: return undefined; } ...
Conclusion
To sum up, the approach described in this blog consists of the following steps at a high level:
Create config.js file with environment variable placeholders in public folder in the React application
Add config.js reference in script tag in index.html
Create shell scripts for rewriting config.js file at runtime
Use scripts in Dockerfile as entry point
With this approach, the React application container will be aware of environment variables at runtime through a dynamically rewritten config.js file. The obvious benefit of the above described approach is that only one container is built and reused for various environments depending on runtime variables and also build time will be shortened significantly.
- Special thanks to Sergey Grebenshchikov for review and suggestions -
Der Beitrag Making a React application container environment-aware at Kubernetes deployment erschien zuerst auf codecentric AG Blog.
Making a React application container environment-aware at Kubernetes deployment published first on https://medium.com/@TheTruthSpy
0 notes
Photo
Vue.js+TypeScriptのコンポーネントのクラス定義ミスでハマった話 https://ift.tt/2J0joZV
概要
export default class Hoge extends Vue {} のクラス定義をミスった際に不思議な挙動をしたので、覚書。
教訓
Vueファイルをコピーしたらクラス名を変更し忘れないようにしよう。
GitHubに利用したプロジェクトをUPしています。実際に試してみたい方どうぞ^^ https://github.com/kai-kou/vue-js-typescript-component-class-name
準備
ここではDockerを利用して環境構築していますが、ローカルで構築してもらってもOKです。
> mkdir 任意のディレクトリ > cd 任意のディレクトリ > vi Dockerfile > vi docker-compose.yml
Dockerfile
FROM node:10.8.0-stretch RUN npm install --global @vue/cli WORKDIR /projects
docker-compose.yml
version: '3' services: app: build: . ports: - "8080:8080" volumes: - ".:/projects" tty: true
> docker-compose up -d > docker-compose exec app bash
コンテナ内
> vue create app Vue CLI v3.0.1 ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, TS, Linter, Unit ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript for auto-detected polyfills? Yes ? Pick a linter / formatter config: TSLint ? Pick additional lint features: Lint on save ? Pick a unit testing solution: Mocha ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No ? Pick the package manager to use when installing dependencies: (Use arrow keys) ❯ Use Yarn Use NPM
コンテナ内
> cd app
これで環境が整いました。
検証
新しくコンポーネントを追加します。
> touch src/components/Hoge.vue
src/components/Hoge.vue
<template> <div>hoge</div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; @Component export default class Hoge extends Vue {} </script>
追加したコンポーネントをコピーしてもうひとつ追加します。
> cp src/components/Hoge.vue src/components/Hoge2.vue
あえて、export default class Hoge extends Vue {} のHoge をそのままにしておきます。
src/components/Hoge2.vue
<template> <div>hoge2</div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; @Component export default class Hoge extends Vue {} </script>
もとからあるApp.vueで追加したコンポーネントを利用します。
src/App.vue
<template> <div id="app"> <hoge/> <hoge2/> <img alt="Vue logo" src="./assets/logo.png"> <HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; import HelloWorld from './components/HelloWorld.vue'; import Hoge from './components/Hoge.vue'; import Hoge2 from './components/Hoge2.vue'; @Component({ components: { HelloWorld, Hoge, Hoge2, }, }) export default class App extends Vue {} </script> (略)
ブラウザで確認してみます。
> yarn serve yarn run v1.9.2 $ vue-cli-service serve INFO Starting development server... Starting type checking and linting service... Using 1 worker with 2048MB memory limit 98% after emitting CopyPlugin DONE Compiled successfully in 67085ms 7:53:09 AM No type errors found No lint errors found Version: typescript 3.0.3, tslint 5.11.0 Time: 28863ms App running at: - Local: http://localhost:8080/ It seems you are running Vue CLI inside a container. Access the dev server via http://localhost:<your container's external mapped port>/ Note that the development build is not optimized.
はい。 追加コンポーネントが表示されました。 追加した2つのコンポーネントのClass名はHoge で同じなのですが、特にエラー出力はありません。
単体テストを追加してみます。
> touch tests/unit/App.spec.ts
tests/unit/App.spec.ts
import { expect } from 'chai'; import { shallowMount } from '@vue/test-utils'; import App from '@/App.vue'; import HelloWorld from '@/components/HelloWorld.vue'; import Hoge from '@/components/Hoge.vue'; import Hoge2 from '@/components/Hoge2.vue'; describe('App.vue', () => { it('Hogeコンポーネントが表示されるか', () => { const wrapper = shallowMount(App, {}); wrapper.is(App); expect(wrapper.findAll(HelloWorld)).to.length(1); expect(wrapper.findAll(Hoge)).to.length(1); expect(wrapper.findAll(Hoge2)).to.length(1); }); });
テスト実行してみます。
> yarn test:unit WEBPACK Compiled successfully in 1101ms MOCHA Testing... App.vue 1) Hogeコンポーネントが表示されるか 0 passing (1s) 1 failing 1) App.vue Hogeコンポーネントが表示されるか: AssertionError: expected { Object () } to have a length of 1 but got 2 + expected - actual -2 +1 at Context.<anonymous> (dist/webpack:/tests/unit/Hoge.spec.ts:15:1) MOCHA Tests completed with 1 failure(s)
oh。 Hogeコンポーネントが2つとみなされました。 そりゃあ、そうクラス定義しているので、そうですね。 けど、単体テストを書かないと気が付かずにそのまま。。。になりかねないので、 皆さま、うっかりミスには気をつけましょう^^
参考
Vue.js+TypeScriptで開発するときの参考記事まとめ https://cloudpack.media/43084
元記事はこちら
「Vue.js+TypeScriptのコンポーネントのクラス定義ミスでハマった話」
October 16, 2018 at 04:00PM
0 notes
Link
<!–IBM launches resources for cloud-native Node.js apps | ITworld
The open source repos help developers build and deploy cloud-native Node.js applications via Docker containers and Kubernetes orchestration
Thank you
Your message has been sent.
Sorry
There was an error emailing this page.
Popartic / Getty Images
“); }); try { $(“div.lazyload_blox_ad”).lazyLoadAd({ threshold : 0, // You can set threshold on how close to the edge ad should come before it is loaded. Default is 0 (when it is visible). forceLoad : false, // Ad is loaded even if not visible. Default is false. onLoad : false, // Callback function on call ad loading onComplete : false, // Callback function when load is loaded timeout : 1500, // Timeout ad load debug : false, // For debug use : draw colors border depends on load status xray : false // For debug use : display a complete page view with ad placements }) ; } catch (exception){ console.log(“error loading lazyload_ad ” + exception); } });
IBM’s new CloudNativeJS project seeks to help developers build and deploy cloud-native Node.js applications via Docker containers and Kubernetes orchestration.
The open source effort is intended to provide tools, best practices, and assets to make it easier to build enterprise-grade applications in the cloud.
The CloudNativeJS project’s current assets include:
Node.js module insights, providing testing, verification, and analysis against current LTS (long term support) versions of Node.js across a set of operating systems and architectures. Module Insights also checks and reports code coverage and verifies the license in the module and all dependencies. Developers can view the state of a range of modules.
CloudNative Module LTS policy, intended to offer clarity to module owners and consumers on how long essential fixes should be provided on major versions once a new major version is released. IBM wants this approach to become standard in the Node.js community.
Template Dockerfiles, to implement best practices for building development, debug, test, and production production Docker images for applications.
Template helm charts, to simplify the process of taking a Docker image of an application and deploying it to Kubernetes along with configuration for replicas and autoscaling. Templates also provide configuration for using readiness-based health checking, Prometheus metrics, OpenTracing with Zipkin, and support for using addition cloud-native technologies such as Istio.
Health check support, featuring cloud-health and cloud-health-connect repositories that provide NPM modules to manage and report the life cycle of an application. These are used by Kubernetes to determine if an application is ready to receive requests, to determine whether it is no longer live and should be restarted, and to handle graceful shutdown when requested.
Prometheus monitoring, featuring a repository providing an NPM module for collecting metric data from an application. Metrics range from resource metrics such as CPU and memory to application-level metrics including HTTP request responsiveness. These are exposed as an application endpoint and collected by a Prometheus monitoring project.
OpenTrace request tracking, with the appmetrics-zipkin repository to instrument an application with OpenTracing-based request tracking. Requests can be monitored across microservices and applications.
Where to download CloudNativeJS resources
You can download CloudNativeJS resources from the CloudNativeJS.io website and GitHub.
This story, “IBM launches resources for cloud-native Node.js apps” was originally published by
InfoWorld.
Paul Krill is an editor at large at InfoWorld, whose coverage focuses on application development.
ITWorld DealPost: The best in tech deals and discounts.
ITworld
Follow us
Copyright © 2018 IDG Communications, Inc.
Explore the IDG Network descend
<a style="display:none" rel="follow" href="http://megatheme.ir/" title="قالب وردپرس">قالب وردپرس</a>
The post IBM launches resources for cloud-native Node.js apps appeared first on MusicCosmoS.
0 notes
Text
a minikube dev envionment and workflow
window.location.replace("https://blog.sebastianfromearth.com/post/20180523065409");
Set up your local kubernetes environment
Add this to your /etc/hosts file somewhere: IMPORTANT - note that the ip address may be 192.168.99.101 or 192.168.99.102, etc, depending on how many times you have recreated your environment locally. Use the appropriate value.
192.168.99.100 dev.myapp.com
Minikube requirements (one of):
virtualbox (at least version 5) vmwarefusion kvm (driver installation) xhyve (driver installation)
Install kubectl, helm & minikube: IMPORTANT - please make sure you are using minikube version 0.24.1
### MAC # kubectl curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.9.0/bin/darwin/amd64/kubectl; chmod +x ./kubectl; sudo mv ./kubectl /usr/local/bin/kubectl # kubernetes-helm sudo curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.7.2-darwin-amd64.tar.gz; sudo tar -zxvf helm-v2.7.2-darwin-amd64.tar.gz; sudo mv darwin-amd64/helm /usr/local/bin/helm # minikube curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.24.1/minikube-darwin-amd64; chmod +x minikube; mv minikube /usr/local/bin/minikube ### Linux # kubectl sudo curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.9.0/bin/linux/amd64/kubectl; sudo chmod +x ./kubectl; sudo mv ./kubectl /usr/local/bin/kubectl # kubernetes-helm sudo curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.7.2-linux-amd64.tar.gz; sudo tar -zxvf helm-v2.7.2-linux-amd64.tar.gz; sudo mv linux-amd64/helm /usr/local/bin/helm # minikube sudo curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.24.1/minikube-linux-amd64; sudo chmod +x minikube; sudo mv minikube /usr/local/bin/minikube
Start minikube, sync the project directory's files into the minikube VM and load the dashboard: IMPORTANT - please make sure you use kubernetes version v1.8.0
minikube start --memory 4096 --kubernetes-version v1.8.0 rsync -av --numeric-ids --stats -e "ssh -i $(minikube ssh-key)" --rsync-path="sudo rsync" /my/project/dir/ docker@$(minikube ip):/myprojectdir/ minikube dashboard
Add an nginx ingress controller into your local kubernetes cluster, as well as heapster:
minikube addons enable ingress minikube addons enable heapster
Install tiller into your local kubernetes cluster:
helm init
You just saw this rsync command above:
rsync -av --numeric-ids --stats -e "ssh -i $(minikube ssh-key)" --rsync-path="sudo rsync" /my/project/dir/ docker@$(minikube ip):/myprojectdir/
The workflow here is to sync the files, rather than mount, with the minikube vm. This is because on a mac, mounting is way too slow with docker, especially for node projects. Once the files have been synced into the minikube vm, we can mount them into local docker containers which will be used in the minikube k8s cluster.
Let's take a node project as an example.
Development Workflow
We will do work on our host, using a ide/text editor on the host and also node/npm on the host. We will use the minikube docker daemon, and we will rsync changed files into the minikube vm.
Change to the root of your app project directory on your host:
cd /my/node/project/dir/
Build this example node application using the npm installed on your host:
npm i; npm run build
Re-sync any changed files into the minikube vm: IMPORTANT - remember to do this each time, maybe can be added in the package.json (I didn't make any hot change functionality yet).
rsync -av --numeric-ids --stats -e "ssh -i $(minikube ssh-key)" --rsync-path="sudo rsync" /my/project/dir/ docker@$(minikube ip):/myprojectdir/
Use minikube's docker daemon:
eval $(minikube docker-env)
Build your dev docker image inside the minikube VM:
docker build -t my-node-app -f Dockerfile.dev .
The dockerfile might look something like:
FROM node:8.9 as builder RUN node -v && npm -v FROM nginx:1.12 COPY ./nginx.conf /etc/nginx/nginx.conf
...and the nginx config might look something like:
worker_processes auto; events { worker_connections 1024; } error_log /dev/stdout debug; http { include mime.types; sendfile off; server_tokens off; server { listen 8080; access_log /dev/stdout; error_log /dev/stdout; client_max_body_size 0; location / { root /var/www; try_files $uri $uri/ =404; index index.html; } } }
Deploy the node app to your minikube kubernetes environment:
helm upgrade --install --values helm/myapp/values/dev.yaml --namespace dev dev helm/myapp
The missing part you might be wondering about is how the docker container is serving the built html/css/js files. It's in the helm chart, using a persistent volume mount and persistent volume claim:
--- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: my-node-app namespace: {{ .Release.Namespace }} labels: env: {{ .Release.Namespace }} role: my-node-app app: my-node-app spec: replicas: {{ .Values.nodeApp.replicaCount }} strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 1 template: metadata: labels: env: {{ .Release.Namespace }} role: my-node-app app: my-node-app spec: containers: - name: my-node-app image: {{ .Values.nodeApp.imageName }}:{{ .Values.nodeApp.dockerImageVersion }} {{ if eq .Values.env "dev" }} volumeMounts: - mountPath: /var/www name: app-volume {{ end }} imagePullPolicy: {{ .Values.imagePullPolicy }} resources: requests: memory: {{ .Values.nodeApp.memory.requests }} cpu: {{ .Values.nodeApp.cpu.requests }} limits: memory: {{ .Values.nodeApp.memory.limit }} cpu: {{ .Values.nodeApp.cpu.limit }} ports: - containerPort: {{ .Values.nodeApp.port }} name: http {{ if eq .Values.env "dev" }} volumes: - name: app-volume persistentVolumeClaim: claimName: app-claim {{ end }} --- apiVersion: v1 kind: PersistentVolume metadata: name: app-volume spec: storageClassName: app-manual accessModes: - ReadWriteOnce capacity: storage: 250Mi hostPath: path: /myprojectdir/web
Values:
env: dev imagePullPolicy: IfNotPresent nodeApp: replicaCount: 1 cpu: requests: 100m limit: 200m memory: requests: 100Mi limit: 200Mi port: 8080 imageName: my-node-app dockerImageVersion: latest
Now every time we edit our application and make a change, we can rebuild it, resync it and redeploy it with helm (which mounts the files into the running pod). I admit this isn't exactly seemless, but it is possible to work like this in a k8s style environment.
A large upside (from an ops perspective) is that you can then use the same helm chart, with different values files to provision separate environments. You could even package the whole thing as a helm chart to be stored in the chart museum for one line installation of an entire environment.
Each environment will be the same, they will all use the same tooling ecosystem, and your infrastructure changes can be tracked and committed to a git repository. If you want to make sure your dev environment is as close as possible to your qa, staging, prod or any other environments you are running with, this might be a viable skeleton of an option.
Resetting Everything
To remove the app from your minikube kubernetes cluster:
helm del --purge dev
To destroy everything and reset completely:
minikube stop minikube delete rm -rf ~/.minikube rm -f ~/.kube/config
0 notes
Photo
An Exhaustive Guide to Writing Dockerfiles for Node.js Web Apps ☞ https://blog.hasura.io/an-exhaustive-guide-to-writing-dockerfiles-for-node-js-web-apps-bbee6bd2f3c4 #Javascript #Nodejs
0 notes
Photo
Vue.js+TypeScriptでElement-ui利用時に単体テストが完了しなくて悩んだ話 https://ift.tt/2OiJuNJ
概要
Vue.js+TypeScriptでElement-ui利用なプロジェクトで単体テストを書いてたらテストが完了せずにハマったので覚書です。
Elementについては下記をご参考ください。
Element http://element.eleme.io/#/en-US
Vue.jsのコンポーネント詰め合わせ「Element」がスゴかった https://s8a.jp/vue-js-library-element
すべてを調べてないので、あれですが、ElementのLoadingコンポーネントをServiceとして利用する場合、close メソッド内で、setTimeout を利用しているのでnextTick を忘れないようにしましょう(結論) http://element.eleme.io/#/en-US/component/loading
Githubに検証で利用したプロジェクトをUPしています。よければご参考ください。 https://github.com/kai-kou/vue-js-typescript-element-ui-unit-test
準備
Vue-Cliで環境を作ります。 ここではDockerを利用して環境構築していますが、ローカルで構築してもらってもOKです。
> mkdir 任意のディレクトリ > cd 任意のディレクトリ > vi Dockerfile > vi docker-compose.yml
Dockerfile
FROM node:10.8.0-stretch RUN npm install --global @vue/cli WORKDIR /projects
docker-compose.yml
version: '3' services: app: build: . ports: - "8080:8080" volumes: - ".:/projects" tty: true
> docker-compose up -d > docker-compose exec app bash
単体テストも書くので、Unit Testを忘れずに。
コンテナ内
> vue create app Vue CLI v3.0.1 ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, TS, Linter, Unit ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript for auto-detected polyfills? Yes ? Pick a linter / formatter config: TSLint ? Pick additional lint features: Lint on save ? Pick a unit testing solution: Mocha ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No ? Pick the package manager to use when installing dependencies: (Use arrow keys) ❯ Use Yarn Use NPM
プロジェクトが作成できたら、Elementをインストールします。
コンテナ内
> cd app > yarn add element-ui
これで環境が整いました。
検証
プロジェクト作成すると最初からあるHelloWorldコンポーネントでElementのLoadingコンポーネントを利用します。
画像をクリックするとLoadingが表示されるようにします。 ただ、検証のため、ブラウザではほぼ視認できないかと思います^^
src/components/HelloWorld.vue
(略) @Component export default class HelloWorld extends Vue { @Prop() private msg!: string; private mounted() { const loadingInstance = Loading.service({}); loadingInstance.close(); } } (略)
それでは、単体テストを実行してみます。
コンテナ内
> yarn test:unit MOCHA Testing... HelloWorld.vue ✓ renders props.msg when passed (179ms) 1) renders props.msg when passed 1 passing (2s) 1 failing 1) HelloWorld.vue renders props.msg when passed: Uncaught TypeError: Cannot read property 'split' of undefined at getTransitionInfo (dist/webpack:/node_modules/vue/dist/vue.runtime.esm.js:7003:1) at whenTransitionEnds (dist/webpack:/node_modules/vue/dist/vue.runtime.esm.js:6973:1) at Timeout._onTimeout (dist/webpack:/node_modules/vue/dist/vue.runtime.esm.js:7201:1) MOCHA Tests completed with 1 failure(s)
はい。
テストはパスしているものの、エラーが発生しています。エラーについても、
renders props.msg when passed: Uncaught TypeError: Cannot read property 'split' of undefined
とあり、なんのことかよくわかりません。
原因
とりあえず、ElementのLoadingコンポーネントの実装を眺めてみます。
element-ui/lib/loading.js(抜粋)
LoadingConstructor.prototype.close = function () { var _this = this; if (this.fullscreen) { fullscreenLoading = undefined; } (0, _afterLeave2.default)(this, function (_) { var target = _this.fullscreen || _this.body ? document.body : _this.target; (0, _dom.removeClass)(target, 'el-loading-parent--relative'); (0, _dom.removeClass)(target, 'el-loading-parent--hidden'); if (_this.$el && _this.$el.parentNode) { _this.$el.parentNode.removeChild(_this.$el); } _this.$destroy(); }, 300); this.visible = false; };
(0, _afterLeave2.default) なるものが、なにやら怪しかったので、実装を見てみます。
element-ui/src/utils/after-leave.js(抜粋)
export default function(instance, callback, speed = 300, once = false) { if (!instance || !callback) throw new Error('instance & callback is required'); let called = false; const afterLeaveCallback = function() { if (called) return; called = true; if (callback) { callback.apply(null, arguments); } }; if (once) { instance.$once('after-leave', afterLeaveCallback); } else { instance.$on('after-leave', afterLeaveCallback); } setTimeout(() => { afterLeaveCallback(); }, speed + 100); };
oh。setTimeout ですね。
ここで、Elementのドキュメントのことを思い出しました。
http://element.eleme.io/#/en-US/component/loading
let loadingInstance = Loading.service(options); this.$nextTick(() => { // Loading should be closed asynchronously loadingInstance.close(); });
はい。
this.$nextTick を忘れていました(白目
Loading should be closed asynchronously(ロードは非同期で終了する必要があります) とありますし。
では、HelloWorldコンポーネントを修正します。
src/components/HelloWorld.vue
(略) @Component export default class HelloWorld extends Vue { @Prop() private msg!: string; private mounted() { const loadingInstance = Loading.service({}); this.$nextTick(() => { loadingInstance.close(); }); } } (略)
テストを実行します。
コンテナ内
> yarn test:unit MOCHA Testing... HelloWorld.vue ✓ renders props.msg when passed (535ms) 1 passing (633ms) MOCHA Tests completed successfully
はい。 無事にエラーが発生しなくなりました。
ハマっていた当初はVuexやaxiosも利用していたので、原因はどこだーとあれこれ探って見つけられず仕舞いでしたが、こうやってシンプルな実装で検証すると見つかるものですね。教訓。
参考
Element http://element.eleme.io/#/en-US
Vue.jsのコンポーネント詰め合わせ「Element」がスゴかった https://s8a.jp/vue-js-library-element
Element – Loading http://element.eleme.io/#/en-US/component/loading
Vue.js+TypeScriptで開発するときの参考記事まとめ https://cloudpack.media/43084
元記事はこちら
「Vue.js+TypeScriptでElement-ui利用時に単体テストが完了しなくて悩んだ話」
October 10, 2018 at 02:00PM
0 notes
Photo

TypeScriptなVue.jsで環境ごとに設定ファイルを読み込みこめるようにしてみた https://ift.tt/2xnLl9c
概要
Vue.jsで設定ファイルを環境ごとに読み込みたかった。 以下を参考にTypeScriptでもできるようにしてみました。
Vue.js + webpack で環境ごとに設定ファイルを分ける https://qiita.com/zaru/items/45a94a2d95001cfe5ead
手順
プロジェクト作成
Vue.jsのプロジェクトを作成するところから。Dockerで環境作ってますがローカルで実行しても問題ありません。好みです。
言語やTypeScriptです。じゃないと以下の手順が破綻します^^;;;
GitHubに利用したプロジェクトをUPしています。環境構築が面倒!けど試したい///という方はどうぞ。 https://github.com/kai-kou/vue-js-typescript-global-mixin.git
> mkdir 任意のディレクトリ > cd 任意のディレクトリ > vi Dockerfile > vi docker-compose.yml
Dockerfile
FROM node:10.8.0-stretch RUN npm install --global @vue/cli WORKDIR /projects
docker-compose.yml
version: '3' services: app: build: . ports: - "8080:8080" volumes: - ".:/projects" tty: true
> docker-compose up -d > docker-compose exec app bash
言語をTypeScriptで。あとは適当で良いです。
コンテナ内
> vue create app Vue CLI v3.0.1 ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, TS, Linter ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript for auto-detected polyfills? Yes ? Pick a linter / formatter config: TSLint ? Pick additional lint features: Lint on save ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No ? Pick the package manager to use when installing dependencies: (Use arrow keys) ❯ Use Yarn
設定ファイルの用意
> cd app/ > mkdir src/configs > touch src/configs/development.ts > vi src/configs/development.ts
app/src/configs/development.ts
export default { hoge: { hoge: 'hoge', fuge: 'fuge', }, };
他の環境の設定ファイルも用意します。
> cp src/configs/development.ts src/configs/production.ts > cp src/configs/development.ts src/configs/test.ts
configディレクトリのエイリアス設定
参考にさせてもらった記事だと、Webpack.config.jsに設定を追加する感じだったのですが、Vue-CLI3系はvue.config.jsを利用するみたいです。
> touch vue.config.js > vi vue.config.js
app/vue.config.js
var path = require('path'); module.exports = { configureWebpack: { resolve: { alias: { config: path.resolve(`src/configs/${process.env.NODE_ENV}.ts`), } } } };
tslint対策
このままだとWebpackの設定で追加したaliasをtslintさんが読み取ってくれないので、無視してもらうようにお願いします。ここはもっと良い方法がありそうです。 ファイル名は任意です。
> touch src/types.d.ts > vi src/types.d.ts
src/types.d.ts
declare module 'config';
設定ファイルの読み込み
せっかくTypeScriptを使っているので、ここでは、各コンポーネントの基底クラスを実装してみました。ここももっと良い方法がありそうです。 Vue.jsなのでMixinどうしたらいいのかなぁと悩んでて、以下記事をみつけて、あ〜それでいいのかぁとなりました。感謝!
VueとTypeScriptとMixin https://qiita.com/totto357/items/4b20accb64f926cdfc30
> touch src/components/Base.ts > vi src/components/Base.ts
app/src/components/Base.ts
import Vue from 'vue'; import Component from 'vue-class-component'; import config from 'config'; @Component export default class Base extends Vue { protected config?: any; protected created() { this.config = config; } }
で、ここでは最初から用意されているコンポーネントでconfigが利用できるようにしてみいます。 Baseコンポーネントを継承しても良いのですが、config をそのままインポートでも良いですね。お好みで。
vi src/components/HelloWorld.vue
app/src/components/HelloWorld.vue
<script lang="ts"> +import Component from 'vue-class-component'; -import { Component, Prop, Vue } from 'vue-property-decorator'; +import { Prop, Vue } from 'vue-property-decorator'; +import Base from '@/components/Base'; +import config from 'config'; @Component -export default class HelloWorld extends Vue { +export default class HelloWorld extends Base { @Prop() private msg!: string; } created() { // 継承元から console.log(this.config); // 自前でimport console.log(config); } </script>
では、確認してみましょう。
コンテナ内
> yarn serve
コンテナ外
> open http://localhost:8080/

(ポートが8081なのはご愛嬌^^
やったぜ。
やりようがいくらでもある感じなので、ベストプラクティスはどれ!ってなりがちですが、とりあえずご参考までに。
参考
Vue.js + webpack で環境ごとに設定ファイルを分ける https://qiita.com/zaru/items/45a94a2d95001cfe5ead
VueとTypeScriptとMixin https://qiita.com/totto357/items/4b20accb64f926cdfc30
Vue.js+TypeScriptで開発するときの参考記事まとめ https://qiita.com/kai_kou/items/19b494a41023d84bacc7
元記事はこちら
「TypeScriptなVue.jsで環境ごとに設定ファイルを読み込みこめるようにしてみた」
September 20, 2018 at 12:00PM
0 notes
Photo
Vue.jsでコンポーネントを入れ子にするとUnit Testでワーニングがでて煩わしい https://ift.tt/2PLZ4NQ
概要
コンポーネントを入れ子にするとUnit Testで以下のようなメッセージが表示されるのだけど、繰り返しテストをするときに煩わしいので、黙らせたかった。
[vue-test-utils]: The child component has been modified to ensure it is created with properties injected by Vue Test Utils.
再現手順
Vue.jsのプロジェクトを作成するところから。Dockerで環境作ってますがローカルで実行しても問題ありません、。言語はTypeScriptです。
GitHubに利用したプロジェクトをUPしています。環境構築が面倒!けど試したい///という方はどうぞ。 https://github.com/kai-kou/vue-js-unit-test-stub-warning
> mkdir 任意のディレクトリ > cd 任意のディレクトリ > vi Dockerfile > vi docker-compose.yml
Dockerfile
FROM node:10.8.0-stretch RUN npm install --global @vue/cli WORKDIR /projects
docker-compose.yml
version: '3' services: app: build: . ports: - "8080:8080" volumes: - ".:/projects" tty: true
> docker-compose up -d > docker-compose exec app bash
テストしたいので、? Pick a unit testing solution: でMocha を選んでくださいね。言語もTypeScriptで。
コンテナ内
> vue create app Vue CLI v3.0.1 ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, TS, CSS Pre-processors, Linter, Unit ? Use class-style component syntax? Yes ? Use Babel alongside TypeScript for auto-detected polyfills? Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): SCSS/SASS ? Pick a linter / formatter config: TSLint ? Pick additional lint features: Lint on save ? Pick a unit testing solution: Mocha ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No ? Pick the package manager to use when installing dependencies: (Use arrow keys) ❯ Use Yarn
最初からあるHelloWorldコンポーネントを利用するコンポーネントを作成します。
> touch src/components/Parent.vue > vi src/components/Parent.vue
src/components/Parent.vue
<template> <div> <HelloWorld msg="hoge" /> </div> </template> <script lang="ts"> import { Component, Prop, Vue, } from 'vue-property-decorator'; import HelloWorld from '@/components/HelloWorld.vue'; @Component({ components: { HelloWorld, }, }) export default class Parent extends Vue {} </script>
で、単体テストを用意します。
> touch tests/unit/Parent.spec.ts > vi tests/unit/Parent.spec.ts
tests/unit/Parent.spec.ts
import { shallowMount } from '@vue/test-utils'; import Parent from '@/components/Parent.vue'; describe('Parent.vue', () => { it('コンポーネントを入れ子にすると警告がでる?', () => { const wrapper = shallowMount(Parent, {}); wrapper.is(Parent); }); });
検証
この時点ではまだメッセージはでません。
コンテナ内
> yarn test:unit MOCHA Testing... Parent.vue ✓ コンポーネントを入れ子にすると警告がでる? (320ms) 1 passing (595ms) MOCHA Tests completed successfully
では、再現のため、Parentコンポーネントを利用するコンポーネントを作成します。
> touch src/components/GrandFather.vue > vi src/components/GrandFather.vue
src/components/GrandFather.vue
<template> <div> <parent/> </div> </template> <script lang="ts"> import { Component, Prop, Vue, } from 'vue-property-decorator'; import Parent from '@/components/Parent.vue'; @Component({ components: { Parent, }, }) export default class GrandFather extends Vue {} </script>
で単体テストを用意します。
> touch tests/unit/GrandFather.spec.ts > vi tests/unit/GrandFather.spec.ts
tests/unit/GrandFather.spec.ts
import { shallowMount } from '@vue/test-utils'; import GrandFather from '@/components/GrandFather.vue'; describe('GrandFather.vue', () => { it('コンポーネントを入れ子にすると警告がでる?', () => { const wrapper = shallowMount(GrandFather, {}); wrapper.is(GrandFather); }); });
> yarn test:unit MOCHA Testing... GrandFather.vue [vue-test-utils]: The child component has been modified to ensure it is created with properties injected by Vue Test Utils. This is because the component was created with Vue.extend, or uses the Vue Class Component decorator. Because the component has been modified, it is not possible to find it with a component selector. To find the component, you must stub it manually using the stubs mounting option, or use a name or ref selector. You can hide this warning by setting the Vue Test Utils config.logModifiedComponents option to false. ✓ コンポーネントを入れ子にすると警告がでる? (253ms) 1 passing (268ms) MOCHA Tests completed successfully
ぐぬぬ、1度ならまだしも。毎回でると煩わしいのです。
黙らせる方法
メッセージにもあるとおり、config.logModifiedComponents を利用します。
> vi tests/unit/GrandFather.spec.ts
tests/unit/GrandFather.spec.ts
-import { shallowMount } from '@vue/test-utils'; +import { shallowMount, config } from '@vue/test-utils'; import GrandFather from '@/components/GrandFather.vue'; +config.logModifiedComponents = false;
これで、表示は消えるものの、コンポーネントが増えると面倒ですねー。 他に良い方法はないものなのでしょうか。
Vue.js+TypeScriptで開発するときの参考記事まとめ https://qiita.com/kai_kou/items/19b494a41023d84bacc7
元記事はこちら
「Vue.jsでコンポーネントを入れ子にするとUnit Testでワーニングがでて煩わしい」
September 19, 2018 at 04:00PM
0 notes