GAEのGoでHelloWorld
概要
GCPにいろんなサービスが存在するのはわかったが
とりあえずBookshelfプリケーション作ろうチュートリアル に準じて一通りのサービスを触ってみる。まずはGAE(Go1.12)でHelloWorldしてみるのだ。
ちなみに実験環境は「mac OS Mojave 10.14.6」
事前準備
ブラウザのコンソールよりターミナルからコマンドで実行できた方がかっこいいので
Cloud SDK のインストール に準じてgcloudが実行できる環境を準備
gcloudコマンドのインストール
まずインストール。何か聞かれたら基本「Y」か「何も書かず」Enter
curl https://sdk.cloud.google.com | bash
シェルを再起動
exec -l $SHELL
gcloud環境を初期化。希望するgoogleアカウントでログイン。
gcloud init # [1] Re-initialize this configuration [default] with new settings # [3] Log in with a new account # [1] abstract-hydra-251604
構築
プロジェクトを作ってみよう
ざっとドキュメント見てみたところ
「組織->フォルダ->プロジェクト->GCEとかBigQueryとかいろんなサービス達」こんな構成にできるらしい。
でも組織、フォルダは「G Suite」か「Cloud Identity」契約してないとダメらしい。。
「ucwork->open or private->ucwork-ai-000001->サービス達」こんな感じにしてみたかったけど・・取り急ぎプロジェクトのみで行こう
プロジェクトの新規作成
gcloud projects create ucwork-ai-000002 --name="gae hello world" Create in progress for [https://cloudresourcemanager.googleapis.com/v1/projects/ucwork-ai-000002]. Waiting for [operations/cp.6028126867139483180] to finish...done. Enabling service [cloudapis.googleapis.com] on project [ucwork-ai-000002]... Operation "operations/acf.b0ff89af-10b4-4f38-8221-d4da7b79c559" finished successfully.
プロジェクト一覧確認
gcloud projects list
PROJECT_ID NAME PROJECT_NUMBER
ucwork-ai-000002 gae hello world 298968203397
プロジェクトの詳細
gcloud projects describe ucwork-ai-000002 createTime: '2019-09-23T08:05:31.373Z' lifecycleState: ACTIVE name: gae hello world projectId: ucwork-ai-000002 projectNumber: '298968203397'
デフォルトプロジェクトの確認
デフォルトプロジェクトの設定を確認。
違うプロジェクトが設定されている。さっき作成したプロジェクトをセットしよー
gcloud config list [core] account = [your gmail account] disable_usage_reporting = False project = ucwork-ai-000001 Your active configuration is: [default]
デフォルトプロジェクト設定
さっき作成したプロジェクトをデフォルトプロジェクトに設定
gcloud config set project ucwork-ai-000002
Updated property [core/project].
[core]
account = [your gmail account]
disable_usage_reporting = False
project = ucwork-ai-000002
Your active configuration is: [default]
GAE用のアプリケーション作成
GoでHelloWorldなアプリケーション作成
モデュール初期化
go mod init github.com/shintaro123/ucwork-go
8080ポートの/でアクセスがあった場合のみHelloWorldなアプリケーション
package main import ( "fmt" "log" "net/http" "os" ) func main() { http.HandleFunc("/", indexHandler) port := os.Getenv("PORT") if port == "" { port = "8080" log.Printf("Defaulting to port %s", port) } log.Printf("Listening on port %s", port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil)) } func indexHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } fmt.Fprint(w, "Hello, World!") }
ローカルで実行させてみる
以下の通り実行して
ブラウザでhttp://localhost:8080/
実行すると「Hello, World!」表示されました。
go build ./ucwork-go 2019/09/23 17:32:19 Defaulting to port 8080 2019/09/23 17:32:19 Listening on port 8080
GAEアプリケーションのデプロイ
GAEへのデプロイ条件指示ファイル作成
app.yamlファイル作成
ランタイムだけ指定しとく
runtime: go112
デプロイ実行
デプロイ!
[2] asia-northeast1を選択じゃ!
gcloud app deploy [add_hello_world] You are creating an app for project [ucwork-ai-000002]. WARNING: Creating an App Engine application for a project is irreversible and the region cannot be changed. More information about regions is at <https://cloud.google.com/appengine/docs/locations>. Please choose the region where you want your App Engine application located: [1] asia-east2 (supports standard and flexible) [2] asia-northeast1 (supports standard and flexible) [3] asia-northeast2 (supports standard and flexible) [4] asia-south1 (supports standard and flexible) [5] australia-southeast1 (supports standard and flexible) [6] europe-west (supports standard and flexible) [7] europe-west2 (supports standard and flexible) [8] europe-west3 (supports standard and flexible) [9] europe-west6 (supports standard and flexible) [10] northamerica-northeast1 (supports standard and flexible) [11] southamerica-east1 (supports standard and flexible) [12] us-central (supports standard and flexible) [13] us-east1 (supports standard and flexible) [14] us-east4 (supports standard and flexible) [15] us-west2 (supports standard and flexible) [16] cancel Please enter your numeric choice: 2 Creating App Engine application in project [ucwork-ai-000002] and region [asia-northeast1]....done. Services to deploy: descriptor: [/Users/shintaro.a.uchiyama/project/github.com/shintaro123/ucwork-go/app.yaml] source: [/Users/shintaro.a.uchiyama/project/github.com/shintaro123/ucwork-go] target project: [ucwork-ai-000002] target service: [default] target version: [20190923t175204] target url: [https://ucwork-ai-000002.appspot.com] Do you want to continue (Y/n)? Y Beginning deployment of service [default]... ╔════════════════════════════════════════════════════════════╗ ╠═ Uploading 11 files to Google Cloud Storage ═╣ ╚════════════════════════════════════════════════════════════╝ File upload done. Updating service [default]...failed. ERROR: (gcloud.app.deploy) Error Response: [7] Access Not Configured. Cloud Build has not been used in project ucwork-ai-000002 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=ucwork-ai-000002 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
なんか怒られた...
何やらサービスがdisabledになってるらしいのでenableにしてみる
# サービスから名前絞ってみる gcloud services list --available | grep cloudbuild cloudbuild.googleapis.com Cloud Build API # 対象サービスをenabledにしてみる gcloud services enable cloudbuild.googleapis.com ERROR: (gcloud.services.enable) FAILED_PRECONDITION: Billing must be enabled for activation of service '[cloudbuild.googleapis.com, containerregistry.googleapis.com]' in project '298968203397' to proceed. - '@type': type.googleapis.com/google.rpc.PreconditionFailure violations: - description: "billing-enabled: Project's billing account is not found. https://console.developers.google.com/project/298968203397/settings" subject: '298968203397' type: serviceusage/billing-enabled
また怒られた...先は長いぜ
課金有効にしろ的な感じに見えるな
課金を有効化
課金アカウント一覧確認
gcloud alpha billing accounts list ACCOUNT_ID NAME OPEN MASTER_ACCOUNT_ID 0184D4-9DEE56-138D09 My Billing Account True
今回のプロジェクトに↑のアカウント紐づけてみよう
gcloud alpha billing projects link ucwork-ai-000002 --billing-account 0184D4-9DEE56-138D09 [add_hello_world]
billingAccountName: billingAccounts/0184D4-9DEE56-138D09
billingEnabled: true
name: projects/ucwork-ai-000002/billingInfo
projectId: ucwork-ai-000002
再度サービスを有効化じゃ!
gcloud services enable cloudbuild.googleapis.com [add_hello_world] Operation "operations/acf.5ad913ed-016f-455f-b2c9-c906e0d09d36" finished successfully.
うまくいった!!!この勢いでデプロイじゃ!
2度目の正直。デプロイ
うまくデプロイできた!!!
gcloud app deploy [add_hello_world] Services to deploy: descriptor: [/Users/shintaro.a.uchiyama/project/github.com/shintaro123/ucwork-go/app.yaml] source: [/Users/shintaro.a.uchiyama/project/github.com/shintaro123/ucwork-go] target project: [ucwork-ai-000002] target service: [default] target version: [20190923t195917] target url: [https://ucwork-ai-000002.appspot.com] Do you want to continue (Y/n)? y Beginning deployment of service [default]... ╔════════════════════════════════════════════════════════════╗ ╠═ Uploading 0 files to Google Cloud Storage ═╣ ╚════════════════════════════════════════════════════════════╝ File upload done. Updating service [default]...done. Setting traffic split for service [default]...done. Deployed service [default] to [https://ucwork-ai-000002.appspot.com] You can stream logs from the command line by running: $ gcloud app logs tail -s default To view your application in the web browser run: $ gcloud app browse
以下叩いてブラウザからアクセス!
無事Hello,Worldみれましたわ。
gcloud app browse [add_hello_world] Opening [https://ucwork-ai-000002.appspot.com] in a new tab in your default browser.
まとめ
「独自ドメインの場合どうするの」とか
「app.yamlの設定あんまり理解してない」とか色々あるけど欲張らずちょっとずつ進めてこう。
次はアプリケーションをNoSQLやSQLにつないでみたい
機械脳の時代を読んでみた
概要
AI系企業に勤めることになるので機械脳の時代 を読んでみた。
記憶したことすぐ忘れちゃうので読書感想文書いとく。
読書感想文
「AIの時代ではなく、機械脳の時代」
これからは判断するためのツールではなく、判断自体を機械が行う時代。大きな時代の変革期にある。
これだけ大きなことが起こっている事実を最初に打ち出しながら
機械脳に出来ることを可視化、分類、予測というシンプルな3つに分類しそれぞれ事例を交えて説明してくれている。
著者は実際にデータサイエンスビジネスの前線で活躍している人物なので
モデルがどうとかデータがどうとかいう観点ではなく
ビジネス観点で物事が記載されており非常に勉強になりました。
また、ABCDE、SMART、AICS、RVGCなど
機械脳を設計するためのフレームワークは、データサイエンス未経験者にとっては
拠り所の一つになるためこちらも参考になる。
実際にAIを用いた事業に取り組んだら改めて読んでみよー
GCPってどんなサービスがあるんや
概要
AWS勉強した矢先に、今後はGCP使うことになりそうなのでまずは
GCPドキュメントに記載されてるサービス全部チラ見して自分なりの言葉でメモを残しとこう
(AWSもGCPもたくさんサービスあるのね・・・)
サービス一覧
コンピューティング
IaaS
PaaS
- App Engine
- Go,Javaとかアプリケーション実行できる環境
サーバーレス
- Cloud Functions
- サーバーレスアプリケーション
- Cloud Run(Beta)
- サーバーレスコンテナ
コンテナオーケストラレーション
- Kubernetes Engine
- Dockerコンテナのオーケストラレーション
データベース
NoSQL
- Cloud Datastore
- NoSQLやってみっかって時にとりあえず使ってみるやつ
- Cloud Bigtable
- 高パフォーマンスのNoSQLデータベース
- Cloud Firestore
- NoSQL。Firebaseと絡ませるときに使えるのかなぁ・・
MySQL
- CloudSQL
- リレーショナルデータベースサービス
- Cloud Spanner
- すげぇ高機能・パフォーマンスリレーショナルデータベースサービス
キャッシュ
- Cloud Memorystore
- キャッシュサービス
ストレージ
ブロックストレージ
- Persistent Disk
- Compute Engineのブロックストレージ
オンラインクラウドストレージ
- Cloud Storage
- いろんなデータ入れ込める場所
- Cloud Storage Nearline
- アクセス頻度少ないデータ入れる場所
- Cloud Storage Coldline
- アクセス頻度がめちゃ少ないデータ入れる場所
ファイルサーバー
- Cloud Filestore
- NFS サーバー
データ分析
ビッグデータ解析
- Google データポータル
- 様々なデータソースをダッシュボードで表示できる素敵なやつ
- BigQuery
- データウェアハウス。SQL使えるらしい。
- BigQuery BI Engine(Beta)
- BI(Google データポータル等)とBigQueryの接続キャッシュしてくれたりする素敵なやつ
- Cloud Datalab
- Jupyterノートブックをwebで実行
- Google Genomics
- 大規模な遺伝子データ分析ができるらしい。おらはきっと使わぬだろう
pub/sub
- Cloud Pub/Sub
- メッセージングミドルウェア、キューをためて順次さばいてくれるやつ
データ処理
- Cloud Composer
- ワークフローを作成、スケジュール設定、モニタリング
- Cloud Data Fusion(Beta)
- ETL(Extract/Transform/Load)ツール
- Cloud Dataflow
- ストリーム・バッチでのデータ変換処理
- Cloud Dataproc
- バッチでのデータ変換処理
- Cloud Dataprep
- TRIFACTAなるツールを使ってデータを事前準備(変換)するサービス
AI と ML
AI Platform
Cloud TPU
- TensorFlowに最適化されたマシン(ハード)のこと
AI Platform Deep Learning VM Image
- ディープ ラーニング アプリ用に事前構成されたCE
AI Platform のトレーニングと予測
- TensorFlow、scikit-learn、XGBoostなどをGCPで実行できるらしい
BigQuery ML
AI Platform Data Labeling Service(beta)
AI Hub
- Google Cloud 上で AI の探索、共有、デプロイを行う
プリパッケージ ソリューション
- Cloud Talent Solution
- 募集中の職位の条件に一致する候補者を探す
AI ビルディング ブロック
Cloud AutoML
- より簡単なカスタム ML モデル
Cloud Vision
- 画像投げるとai使って画像分析した情報が返ってくるらしい
Cloud Video Intelligence
- 動画投げるとai使って動画分析した情報が返ってくるらしい
Cloud Natural Language
- 自然言語(普段の会話)を解析・分析して情報返してくれるらしい
Cloud Translation
- テキスト入れると翻訳してくれるらしい
Cloud Speech-To-Text
- 音声をテキストに変換してくれるらしい
Cloud Text-To-Speech
- テキストを音声に変換してくれるらしい
Dialogflow
- 足りない情報を聞き返してくれたり、表現を統一したりしてくれるらしい
Recommendations AI(Beta)
- 個人に特化したおすすめの商品情報を幅広く提供
Cloud Inference API
- なんだかわからんが大規模な相関関係がわかるAPIらしい
ML for Developers
- チュートリアルとデモ。やってみよー
ネットワーキング
GCP内のネットワーク構成
外部ネットワークとの接続
アディショナルなネットワーク関連サービス
- Cloud Armor
- DDos対策
- Traffic Director(Beta)
- マイクロサービス間の通信を管理するサービスメッシュ
- Network Service Tiers
- ネットワークのパフォーマンス落としてコスト最適化するスタンダード階層や現在のプレミアム階層を選択できる
セキュリティと ID
アクセスコントロール
セキュリティチェック
アクセスの透明性
- Googleがアクセスしてきたことをログに残す
Cloud Data Loss Prevention(DLP)
- 機密データを検出して分類。秘匿化もできる
Cloud Identity-Aware Proxy
- GoogleAcountで認証(アクセス制御)ができる
ID プラットフォーム
- メアド・パスワード、電話番号IDなど様々な認証方式で認証(アクセス制御)ができる
Cloud Security Command Center
- 各リソースのセキュリティ脅威をスキャンしてくれるやつ
Binary Authorization
- GKEへのイメージデプロイにおいて署名されたもののみ許可する
Cloud Security Scanner
- コンピューター系リソースのセキュリティ脅威。スキャン
ID管理
Cloud IAM
- 誰(ID)がどのリソースに対するどのようなアクセス権限(役割)を持つかを定義
Cloud Key Management Service
- 暗号化キーの作成・管理ができる
Resource Manager
- 組織・フォルダ・プロジェクトなどのリソース階層をAPIで作成して管理できる
セキュリティキーの適用
- 物理的なセキュリティーキーをUSBとかにぶっさして2段階認証できる
モノのインターネット
- Cloud IoT Core
- IoTのT、デバイスからのデータを受けてくれるサービス。pub/sub->Cloud Functionなどに連携される
GCPへの移行
Google Transfer Appliance
BigQuery Data Transfer Service
Storage Transfer Service
Velostrata
メディアソリューション
オープンソース
観測系
istio
- 複雑なサービスメッシュの監視、認証、ロードバランシングを行ってくれる
OpenCensus
- クラウド上でのメトリクス(平均100msで処理終了などのマクロ情報)とトレーシング(どの処理がどの順番、秒数で終わっているかなど)を観測できる
コンテナ系
gVisor
- セキュアなコンテナランタイム。デフォルトのruncではなくrunscを用いてアプリケーションからハードウェアを制御ある
-
- コンテナオーケストラレーションエンジン
knative
- kubernetes上でサーバーレスアプリケーションをビルドしてデプロイしてくれるらしい
Kubeflow
- kubernetes上でMLが実行できるそうだ
GCPサービスとの関連系
Apache Beam
- Cloud Dataflowでデータ処理の並列パイプラインを定義したりする統合モデル
gRPC
- Protocol Buffersによりデータをシリアライズして高速なRPCを実現
TensorFlow
デベロッパー ツール
開発運用ツール
ソース・イメージ管理
- Cloud Source Repositories
- Git Repository
- Container Registry
- プライベート コンテナの登録と保存
ローカルツール拡充サービス
- Cloud Code for IntelliJ
- Cloud Tools for PowerShell
- PowerShell GCP ツール
- Cloud Tools for Visual Studio
- Visual Studio GCP ツール
- Cloud Tools for Eclipse
- Gradle App Engine Plugin
- Gradle 用 App Engine プラグイン。GAEでビルド、デプロイができる
- Maven App Engine Plugin
管理ツール
GCPリソース管理系
- Cloud Console
- ウェブベースの管理コンソール
- Cloud Shell
- ブラウザベースのコマンドライン ツール
- Google Cloud API
- Cloud Billing
- 請求 / コスト管理ツール
運用・開発ツール
- Cloud Deployment Manager
- アプリケーションのリソースをコード出かける。いわゆるIaaS
- Anthos
監視系
Stackdriver Debugger
- 本番環境でのライブデバッグができるらしい。すげえ
Stackdriver Error Reporting
- アプリエラーの報告
Stackdriver Logging
- ログの一元管理
Stackdriver Monitoring
- インフラストラクチャとアプリケーションのモニタリング
Stackdriver Profiler
- CPU とヒープのプロファイリング
Stackdriver Trace
- アプリケーション パフォーマンスの分析情報
API プラットフォームとエコシステム
Apigeeの製品
- API アナリティクス
- API 収益化
- API使用での収益創出のためのサポートツール
- Apigee API プラットフォーム
- フル ライフサイクルの API 管理プラットフォーム
- デベロッパー ポータル
- API 管理ポータル
- Apigee Sense
Cloud Endpoints
GCP Marketplace
- プライベート カタログ
- マーケットプレイスとは違い、社内とか内部向けにソフトウェア提供するやつ
医療
- Cloud Healthcare API
- 医療関係のデータを素敵に扱えるサービスっぽい
SAP
省略
まとめ
だめだ。多すぎて全然入ってこない。
とりあえず以下ステップで学習を進めよう
- アプリケーションが動く環境の構築
- GCE,GKEなど同系のいろんなサービスを適当してみる
- AI学習しアプリケーションに取り込む
2ヶ月でAWS 認定ソリューションアーキテクト – アソシエイトに合格してきた(2019/08/14)
概要
仕事で完全AWS環境!!とかいう保守運用案件を回されたが
EC2!RDS!S3!とかものすごいポイント・ポイントしか理解していない状態だったので
せっかくなら体系的に学びたいと思いお勉強。
結果的には1発で受かったがかなりギリギリだったのでもっと勉強法見直せばよかったなという反省日記。
勉強方法
結果的には以下「やったこと」の勉強を経て1発で合格できたが
今振り返ると「やっとけばよかった」に記載された内容をやっておけば
あんなに冷や汗かかずに本番挑めたのになーという反省
やったこと
- 徹底攻略 AWS認定ソリューションアーキテクト アソシエイト教科書 - インプレスブックス を3周くらい読み込む
- 本に掲載されてた模擬試験も2週
- とりあえずこういう黒い本やっとけば受かるんでしょっていう甘い考えだった
- AWS WEB問題集で学習しよう | 赤本ではなく黒本の問題集から学習する方向け のフリープランで行けるとこまで全部やる
- Amazon AWS 資格取得のための演習問題集(完全無料、オリジナル) を80問くらいまで頑張る
- 結構細かめの内容を問われる問題も多く、心が折れて80問目で挫折
- AWS公式の模擬試験を受ける
- 極力お金かけたくなかったけど、他のブログ見たら絶対受けろって書いてあるしビビって2000円pay
- 結果的に受けといてよかった。受けずに落ちてたら100%後悔してた
- 問題内容後でみれないので全部スクショ撮って後で復習
- なにこれ見かたわからんけど、合格80%?私は77%?落ちたってこと・・?わからん!
- 極力お金かけたくなかったけど、他のブログ見たら絶対受けろって書いてあるしビビって2000円pay
やればよかったこと
- AWS WEB問題集で学習しよう | 赤本ではなく黒本の問題集から学習する方向け のお金払うプランでゴリゴリ問題とく
- でも一番安いゴールドプランで3,880円(税抜き)なんだよなぁ
- ただ、これやっとけばきっと本番精神的には安定したのかな。お財布と要相談
- もしくはもう何冊か別の本買っていろんな角度の問題に慣れる
かかったコスト
20,930円(受験料:16,200円+模擬試験:2,160円+参考書:2,570円)
勉強期間
ざっと2ヶ月
6月ごろに本買って勉強開始
通勤時間や休みの空いた時間に本読んだりして、1回受けようとしてたこと忘れるくらい仕事忙しくなって
また気力を取り戻して、最後に1週くらいに頭に詰め込み詰め込みでざっと2ヶ月!!
所感
「やればよかった」にも書いたけどもっといろんな問題解いとけばよかった。
UMTPとかOracleJavaの時は正直黒い本だけで行けた感あったけどAWSは黒い本だけだと少し不安が残る気がした(勝手な感想)
あの手この手で最適な解を聞いてくる問題なので、表面的に言葉を覚えるより 「どういう時にこのサービスは使われるのか」みたいな思考をもっと高めるべきだった。
仕事がドタバタして通勤時間と休日少し時間あるときぐらいしか勉強できなかったが
なんとか試験に受かってよかった。すこし余裕も出てきたので勉強再開しよう!!
awesome-typescript-loader,tslintからts-loader,eslintに乗り換える
概要
GWなのでちょいちょい噂になってた以下2点対応しようと思う
- awesome-typescript-loader -> ts-loaderに変更
- もうawesomeなスピードじゃないし、ソースの更新も止まってるらしい
- tslint->eslintに変更
- typescriptチームが正式にeslintにするって言ったとかどうとか
ts-loader対応
ts-loaderインストール
$ npm install --save-dev ts-loader
ts-loaderを使用する設定
webpack.config.jsで 「use: 'awesome-typescript-loader',」を「use: 'ts-loader',」に変更するだけで行けた。
webpack.config.js
module: { // ファイルタイプに対するloaderの設定 rules: [ { test: /\.tsx?$/, use: 'ts-loader', },
eslint対応
eslintとeslint-loaderのインストール
linterであるeslint自体と、webpackから対象ファイルを読み込むためのeslint-loaderをインストール
npm install --save-dev eslint eslint-loader
eslint-loaderの設定
webpack.config.jsで以下の通りruleを指定
enforce:pre
でts-loaderが走り出す前に実行test: /\.(js|ts|jsx|tsx)$/,
で対象になりそうな拡張子全部指定exclude: /node_modules/,
でnode_modulesは対象外にする
webpack.config.js
module: { // ファイルタイプに対するloaderの設定 rules: [ { enforce: "pre", test: /\.(js|ts|jsx|tsx)$/, exclude: /node_modules/, loader: "eslint-loader", }
eslint自体の設定
まずは最小の設定
こんな感じで最小設定してみる
"root": true
で親階層の設定を見に行かない(同階層の設定ファイルを優先)"env": {}
でglobalな変数をeslintに理解させる"es6": true,
でes6形式に記述してもeslintに怒られなくなる"browser": true
でdocument,consoleなど記載しても怒られない
"extends": ["eslint:recommended",
でおすすめlinter設定"parserOptions": {"sourceType": "module"}
でES6を有効化
.eslintrc
{ "root": true, "env": { "es6": true, "browser": true }, "extends": [ "eslint:recommended" ], "parserOptions": { "sourceType": "module" } }
webpack実行すると10:5 error Parsing error: Unexpected token <
が出てくる。
ReactのFragment Shortcut<>
のとこで怒られた
$ # package.jsonの以下script実行 $ # "scripts": { "build": "webpack", $ npm run build 10:5 error Parsing error: Unexpected token <
Reactエラーが出ないように対応させる
@typescript-eslint/eslint-plugin
でeslintをReactにも対応させられそう。
でもこれを動かすには@typescript-eslint/parser
もインストールする必要があるらしい。
@typescript-eslint/typescript-estree
を入れるとパースするときにAST(Abstract Syntax Tree)として取り扱えるらしい。なんのこっちゃ。とりあえず入れとく。
$ npm install --save-dev @typescript-eslint/parser @typescript-eslint/typescript-estree @typescript-eslint/eslint-plugin
extendsに"plugin:react/recommended"
を追加する。
pluginsに指定する方式もあるらしいがこれでいこう。
{ "root": true, "env": { "es6": true, "browser": true }, "extends": [ "eslint:recommended", "plugin:react/recommended" ], "parserOptions": { "sourceType": "module" } }
webpack実行すると11:14 error Parsing error: Unexpected token =
が出てくる。
jsxで<div id=""
ってしてるだけなのになんか怒られる。
$ npm run build 11:14 error Parsing error: Unexpected token =
eslintでtypescriptもlintしてくれるように設定
そもそも、eslintがTypeScriptを理解させるための設定入れてないよな。
typescriptのparserを入れ込む
{ "root": true, "env": { "es6": true, "browser": true }, "extends": [ "eslint:recommended", "plugin:react/recommended" ], "parser": "@typescript-eslint/parser", "parserOptions": { "sourceType": "module" } }
webpack実行するとついにエラー消えたしちゃんとjsファイル出力されてる!
まとめ
今回仕事で初めてフロントにも取り組んだけど。
ほんと変化激しい。ちょっと放置してるとduplicateになってるし。
置いてかれないように見つけたらすぐ対応するようにしよう。
golangのチュートリアル解いてみた
概要
Go言語勉強したい!とりあえずチュートリアル2周読んだ!!
理解度を試すために練習問題(Excesise)解いてメモしとく。
わからないとこはこの方の素晴らしい解答をみてやってみる!!!
練習問題やってみた
Basic
Exercise: Loops and Functions
ニュートン法を用いて平方根求めろって言ってる多分。
ニュートン法自体はこの記事がすごくわかりやすかった!!!
ざっくりいうと「ある関数f(x)が0になるためのxを求める式」はx(n+1) = x(n) - f(x)/f'(x)
を繰り返していくことでわかるらしい。
今回の平方根に照らし合わせるとx=√2 <=> 2-x^2=0
なのでf(x)=2-x^2
が0になるためにはx(n+1) = x(n) - (2-x^2/2x)
ってことなんだな。
10回ループして平方根求めてみる
package main import ( "fmt" ) func Sqrt(x float64) float64 { z := 1.0; for i:=0; i<10; i++ { z -= (z*z - x) / (2*z) } return z } func main() { fmt.Println(Sqrt(2)) }
何回ループすれば答えに近づくか調べてみる
初期値のzを色々変えてみて、x(n+1)とx(n)の差分が極めて小さくなるまで繰り返す。
初期値1では5回で終わった。100とかにしたら11回だった。
(まぁ無心でmath.Sqrt使っちゃうだろうけど・・・)
package main import ( "fmt" "math" ) func Sqrt(x float64) float64 { z, count := 1.0, 0 for { prev := z z -= (z*z - x) / (2*z) count++ if math.Abs(z - prev) < 1e-10 { break } } fmt.Println("iterate count: ", count) return z } func main() { fmt.Println(Sqrt(2)) }
Exercise: Slices
いい感じのグラデーションが出るように2次元のSlice作って
2次元のインデックを計算するんじゃ!
package main import "golang.org/x/tour/pic" func Pic(dx, dy int) [][]uint8 { // 8bit(0-255)数値型の配列をdy個保持する2次元配列生成 /* イメージ [ [] [] ... [] <- dy個 ] */ pic := make([][]uint8, dy) // []の数(dy)分ループ for y := range pic { // 8bit(0-255)数値型をdx個保持する配列生成 /* イメージ [0 0 ... 0]<-dx個 */ pic[y] = make([]uint8, dx) // 0の数(dx)分ループ for x := range pic[y] { // x,yのインデックスを操作してグラデーションを作成 /* イメージ [(0,0) (0,1) ... (0,dx-1)] [(1,0) (1,1) ... (1,dx-1)] [(2,0) (2,1) ...(dy-1,dx-1)] */ pic[y][x] = uint8((x+y)/2) // (x+y)/2の代わりにx*yとかx^yすると色合いがぐっと変わる } } return pic } func main() { pic.Show(Pic) }
Exercise: Maps
文章に出現する文字と数の対応Mapを作るのじゃ!
package main import ( "golang.org/x/tour/wc" "strings" ) func WordCount(s string) map[string]int { // 文字と出現回数格納用のmap生成 wordCountMap := make(map[string]int) // strings.Fieldsで文章を文字で分割 // 文字数分だけループして出現回数カウント for _, word := range strings.Fields(s) { wordCountMap[word]++ } return wordCountMap } func main() { wc.Test(WordCount) }
Exercise: Fibonacci closure
フィボナッチな数字が帰ってくるようにするのじゃ!
package main import "fmt" // fibonacci is a function that returns // a function that returns an int. func fibonacci() func() int { // フィボナッチの2項目(保持される値) n, afterN := 0, 1 return func() int { // 計算のために現状の2項目を一時保存 snapN, snapAfterN := n, afterN // 現状の2項目を次の1項目に格納 // 現状の1項目+2項目を次の2項目に格納 n, afterN = snapAfterN, snapN + snapAfterN // 0から出力されるように一時保存しておいた現状の1項目返却 return snapN } } func main() { f := fibonacci() for i := 0; i < 10; i++ { fmt.Println(f()) } }
Methods and interfaces
Exercise: Stringers
Stringメソッドを実装することで
fmt.Printf
した時にいい感じ(1.1.1.1)に表示されるようにするのじゃ
package main import "fmt" type IPAddr [4]byte // TODO: Add a "String() string" method to IPAddr. func (ip IPAddr) String() string { return fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]) } func main() { hosts := map[string]IPAddr{ "loopback": {127, 0, 0, 1}, "googleDNS": {8, 8, 8, 8}, } for name, ip := range hosts { fmt.Printf("%v: %v\n", name, ip) } }
Exercise: Errors
平方根求めるやつでマイナスの数値来た時にError投げるようにする!!
(float64でキャストしないとループしちゃうのなんでや・・・)
package main import ( "fmt" "math" ) // エラー用のtype宣言 type ErrorNegativeSqrt float64 // エラー投げられた時に出力されるやつ func (e ErrorNegativeSqrt) Error() string { // float64でキャストしなきゃいけないらしい。Why return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e)) } func Sqrt(x float64) (float64, error) { if x < 0 { return 0, ErrorNegativeSqrt(x) } z, count := 1.0, 0 for { prev := z z -= (z*z - x) / (2*z) count++ if math.Abs(z - prev) < 1e-10 { break } } return z, nil } func main() { fmt.Println(Sqrt(2)) fmt.Println(Sqrt(-2)) }
Exercise: Readers
Aを無限に出力するものを作りなさい!!
package main import "golang.org/x/tour/reader" type MyReader struct{} // TODO: Add a Read([]byte) (int, error) method to MyReader. func (r MyReader) Read(b []byte) (int, error) { for i := range b { b[i] = 'A' } return len(b), nil } func main() { reader.Validate(MyReader{}) }
Exercise: rot13Reader
ROT13で文字列を復号するのじゃ!!
ROT13は文字列の順序操作で暗号化する方式(丸パクリ)
package main import ( "io" "os" "strings" ) type rot13Reader struct { r io.Reader } // io.Copyで読み込む際にこの変換かましてくれる func (rot13 rot13Reader) Read(b []byte) (int, error) { n, err := rot13.r.Read(b) for i, v := range b { switch { case v >= 'A' && v < 'N', v >= 'a' && v < 'n': b[i] += 13 case v >= 'N' && v <= 'Z', v >= 'n' && v <= 'z': b[i] -= 13 } } return n, err } func main() { // io.Reader型で文字列取得 s := strings.NewReader("Lbh penpxrq gur pbqr!") // rot13Reader structに設定 r := rot13Reader{s} // io.Copyに参照渡し io.Copy(os.Stdout, &r) }
Exercise: Images
Sliceで生成した画像をimage.Imageインターフェースで実現するんだ!
これも素晴らしい解答の丸パクリだけど、image.Imageに定義されてるインターフェースに必要なメソッドを実装するだけっぽい。。。
package main import ( "golang.org/x/tour/pic" "image" "image/color" ) type Image struct{} func (i Image) ColorModel() color.Model { return color.RGBAModel } func (i Image) Bounds() image.Rectangle { return image.Rect(0, 0, 256, 256) } func (i Image) At(x, y int) color.Color { return color.RGBA{uint8(x), uint8(y), 255, 255} } func main() { m := Image{} pic.ShowImage(m) }
Concurrency
並行処理ができるみたい。
ちょっと完全に理解しきれてないけどとりあえず解いてみる。
今後いろいろ作りながら適切に理解を深めていこう
Exercise: Equivalent Binary Trees
二分木を用いて並行処理をしてみようみたいなとこ
binary treeを探検して数字を順番に出力
binary treeって左下が自身より小さくて、右下が自身より大きい値で構成されたツリー構造。 ↓こんな感じ。これを並行処理で探検させて1-7を順番に出力する的なこと
4 2 6 1 3 5 7
tree.New(k)使うと1*k, 2*k, ..., 10*k
のbinary treeが生成されるっぽい
channelとclose使ってみる
チュートリアルにあったchannelとclose使うパターンだとこんな感じ。
rangeでくるくる回して、やりたいこと終わったらclose(ch)って感じ
package main import ( "golang.org/x/tour/tree" "fmt" ) // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int) { WalkRecrusive(t, ch) close(ch) } func WalkRecrusive(t *tree.Tree, ch chan int){ if t == nil { return } WalkRecrusive(t.Left, ch) ch <- t.Value WalkRecrusive(t.Right, ch) } // Same determines whether the trees // t1 and t2 contain the same values. // func Same(t1, t2 *tree.Tree) bool func main() { ch := make(chan int) go Walk(tree.New(1), ch) for v := range ch { fmt.Println(v) } }
参考までにだが探索するロジックとしては、こんな感じ
これのイメージが最初全く湧かなかった。再帰的処理に慣れてないのかな・・
1. 頂点(4)を呼び出し walk(tree.New(1), ch) 1.1. 左下(2)を呼び出し walk(tree.Left, ch) 1.1.1. 左下(1)を呼び出し walk(tree.Left, ch) 1.1.1.1. 左下(nil)を呼び出し walk(nil, ch) 1.1.1.1.1 nilだからreturn if tree == nil return 1.1.1.2. 自分の値(1)をchに詰め込み ch <- tree.Value 1.1.1.3. 右下(nil)を呼び出し walk(nil, ch) 1.1.1.3.1. nilだからreturn if tree == nil return 1.1.2. 自分の値(2)をchに詰め込み ch <- tree.Value 1.1.3. 右下(3)を呼び出し walk(tree.Right, ch) ...
channelとselectを使ったパターン
せっかくチュートリアルにもあったしselectでも書いてみる
closeじゃなくて、終了用チャネルに値が入ったら終了してる
package main import ( "golang.org/x/tour/tree" "fmt" ) // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int, chend chan bool) { WalkRecrusive(t, ch) chend <- true } func WalkRecrusive(t *tree.Tree, ch chan int){ if t == nil { return } WalkRecrusive(t.Left, ch) ch <- t.Value WalkRecrusive(t.Right, ch) } // Same determines whether the trees // t1 and t2 contain the same values. // func Same(t1, t2 *tree.Tree) bool func main() { ch := make(chan int) chend := make(chan bool) go Walk(tree.New(1), ch, chend) for { select { case val := <- ch: fmt.Println(val) case <- chend: return } } }
同じ値を格納したBinary Treeか判定
以下条件を満たしたら異なると判定するように実装 - 一方の探索対象だけなくなる - 1から出力していき、値が異なる場合
package main import ( "golang.org/x/tour/tree" "fmt" ) // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int) { WalkRecrusive(t, ch) close(ch) } func WalkRecrusive(t *tree.Tree, ch chan int){ if t == nil { return } WalkRecrusive(t.Left, ch) ch <- t.Value WalkRecrusive(t.Right, ch) } // Same determines whether the trees // t1 and t2 contain the same values. func Same(t1, t2 *tree.Tree) bool { ch1 := make(chan int) ch2 := make(chan int) go Walk(t1, ch1) go Walk(t2, ch2) for { val1, ok1 := <- ch1 val2, ok2 := <- ch2 // どちらかチャネルの値が出切ったら終わり if !ok1 || !ok2 { // 両者falseで数が同じならfalse return ok1 == ok2 } // 値が異なった時点でfalse if val1 != val2 { return false } } } func main() { fmt.Println(Same(tree.New(1), tree.New(1))) fmt.Println(Same(tree.New(1), tree.New(2))) }
Exercise: Web Crawler
fekeFetcherで用意したURLたちをクローリングする。
指定されたurlが存在するか検索する。
存在すれば、その配下ににひもづくurlを取得してまた検索という繰り返し
デフォルトから追記したのは以下処理
- 並行処理
- Crawlメソッドをgo func内で実行
- <- doneChでブロッキング
- 処理が終わればdoneCh <- trueで値突っ込みブロック解除
- 同じURLを二回検索しない対策
- fetched.Lock()でロックしてすでに検索済みではないか確認
package main import ( "fmt" "sync" ) type Fetcher interface { // Fetch returns the body of URL and // a slice of URLs found on that page. Fetch(url string) (body string, urls []string, err error) } type Fetched struct { m map[string]error sync.Mutex } var fetched Fetched = Fetched{ m: make(map[string]error), } // Crawl uses fetcher to recursively crawl // pages starting with url, to a maximum of depth. func Crawl(url string, depth int, fetcher Fetcher) { // 指定した深さ全部終了したら終了 if depth <= 0 { return } // 確認ずみのurlか確認 fetched.Lock() if _, ok := fetched.m[url]; ok { fmt.Printf("fetched already: %s\n", url) fetched.Unlock() return } fetched.Unlock() // 対象URLをフェッチ body, urls, err := fetcher.Fetch(url) fetched.m[url] = err // 対象URLが存在しなければ終わり if err != nil { fmt.Println(err) return } fmt.Printf("found: %s %q\n", url, body) // 並列処理で配下のurlたちを実行 doneCh := make(chan bool) for _, u := range urls { go func(url string){ Crawl(url, depth-1, fetcher) doneCh <- true }(u) <- doneCh } return } func main() { Crawl("https://golang.org/", 4, fetcher) fmt.Println("----------") for url, err := range fetched.m { if err != nil { fmt.Printf("%v failed: %v\n", url, err) } else { fmt.Printf("%v was fetched\n", url) } } } // fakeFetcher is Fetcher that returns canned results. type fakeFetcher map[string]*fakeResult type fakeResult struct { body string urls []string } func (f fakeFetcher) Fetch(url string) (string, []string, error) { if res, ok := f[url]; ok { return res.body, res.urls, nil } return "", nil, fmt.Errorf("not found: %s", url) } // fetcher is a populated fakeFetcher. var fetcher = fakeFetcher{ "https://golang.org/": &fakeResult{ "The Go Programming Language", []string{ "https://golang.org/pkg/", "https://golang.org/cmd/", }, }, "https://golang.org/pkg/": &fakeResult{ "Packages", []string{ "https://golang.org/", "https://golang.org/cmd/", "https://golang.org/pkg/fmt/", "https://golang.org/pkg/os/", }, }, "https://golang.org/pkg/fmt/": &fakeResult{ "Package fmt", []string{ "https://golang.org/", "https://golang.org/pkg/", }, }, "https://golang.org/pkg/os/": &fakeResult{ "Package os", []string{ "https://golang.org/", "https://golang.org/pkg/", }, }, }
Skaffoldでminikubeのローカル環境開発
概要
TLSでの通信も行うことができたのでローカルで開発していきたいが
docker-composeのvolumesみたいにMacとコンテナをマウントさせるすべがなさそう。
ざっと調べるとSkaffoldなるものが良さそうなのでそれを使って開発してみる
また、以下記事にて構築した環境をベースに検証しているのでご承知おき
- kubernetesでローカル環境にNGINX, golang, MySQL環境作ってみる
- minikubeでTLS通信して裏側のNginxでHTTP/2.0を受ける
- KubernetesでGolangのPodにHttp/2を通信
Skaffold導入
設定ファイルを記載してSkaffold実行するとマニュフェストや、Dockerfile、Dockerfile内でcopyされてるバイナリファイルやソースファイルなどの変更を感知してデプロイしてくれる。
Skaffoldのインストール
$ brew install skaffold $ skaffold version v0.26.0
Skaffoldの設定
色々設定できるみたいだが、Dockerfileの場所と、対象のManifestを指定するだけにしておく
apiVersion: skaffold/v1beta7 kind: Config build: artifacts: - image: shintaro0123/nginx context: ./docker/nginx/ - image: shintaro0123/golang context: ./docker/go/ deploy: kubectl: manifests: - nginx-deployment.yaml - go-deployment.yaml
ちなみに、Deploymentにはこんな感じでtag:latestを指定しておく。
Skaffoldが再ビルドするとタグが付いてくるのでlatestにしときゃとりあえず見てくれる
spec: containers: - image: shintaro0123/golang:latest
コマンド実行
$ # このコマンドでwatchしてくれる
$ skaffold dev
開発、デプロイの流れを確認
Nginxの場合
アクセスしてみる
$ curl --resolve nginx.ucwork.local:443:`minikube ip` -k https://nginx.ucwork.local <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>sample page</title> </head> <body> <p>sample page1</p> </body> </html>%
DockerでADDされてるindex.htmlを修正
$ git diff diff --git a/docker/nginx/index.html b/docker/nginx/index.html index 5dc8292..afa1aa0 100644 --- a/docker/nginx/index.html +++ b/docker/nginx/index.html @@ -7,7 +7,7 @@ </head> <body> - <p>sample page1</p> + <p>sample page2</p> </body> </html> \ No newline at end of file $ $ skaffold dev # watchしてた奴が反応始めた!! Generating tags... - shintaro0123/nginx -> shintaro0123/nginx:n-1.0.5-5-g37e6f39-dirty Tags generated in 68.854557ms Starting build... Found [minikube] context, using local docker daemon. Building [shintaro0123/nginx]... Sending build context to Docker daemon 3.072kB Step 1/6 : FROM nginx:1.15.8
もう一回アクセス
sample page2になってる!!!数秒もかからんレベル
$ curl --resolve nginx.ucwork.local:443:`minikube ip` -k https://nginx.ucwork.local <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>sample page</title> </head> <body> <p>sample page2</p> </body> </html>%
Golangの場合
アクセスしてみる
$ curl --resolve go.ucwork.local:443:`minikube ip` -k https://go.ucwork.local url path is id: 1 name: taro id: 2 name: jiro id: 3 name: hanako
DockerでCOPYされてるmainを修正
$ git diff docker/go/main.go diff --git a/docker/go/main.go b/docker/go/main.go index 7aafdd1..2e16314 100644 --- a/docker/go/main.go +++ b/docker/go/main.go @@ -27,7 +27,7 @@ func main() { func handler(w http.ResponseWriter, r *http.Request) { /** URLパス表示 */ - w.Write([]byte("url path is " + r.URL.Path[1:] + "\n")) + w.Write([]byte("access url path is " + r.URL.Path[1:] + "\n")) /** DB接続 */ var dbConnectQuery string $ $ env GOOS=linux GOARCH=amd64 go build main.go $ $ skaffold dev # watchしてた奴が反応始めた!! Generating tags... - shintaro0123/golang -> shintaro0123/golang:n-1.0.5-5-g37e6f39-dirty Tags generated in 51.69ms Starting build... Found [minikube] context, using local docker daemon. Building [shintaro0123/golang]... Sending build context to Docker daemon 7.639MB Step 1/6 : FROM golang:1.11.5 ---> 1454e2b3d01f
もう一回アクセス
access urlになってる!!!
$ curl --resolve go.ucwork.local:443:`minikube ip` -k https://go.ucwork.local access url path is id: 1 name: taro id: 2 name: jiro id: 3 name: hanako
まとめ
docker-composeでホストとコンテナマウントできるんだからk8sもなんか手はあるでしょ。
&コンテナのビルドデプロイを自動化って時間かかっちゃうよなぁって疑心暗鬼だったけど、さすがgoogle先生全然爆速。
詳細までは理解できてないけどとりあえず編集とともにデプロイ自動化されたのでこれでいこう