/// BANGBOO BLOG ///

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31


Web List
k8s on Jun 09, 2021 12:01 AM
GCP Hands Off on May 21, 2021 12:00 AM
GCP on May 20, 2021 9:00 PM
Terrafirma on May 02, 2021 10:14 PM
BigQuery on Feb 21, 2021 1:00 AM
Python on Feb 10, 2021 7:30 PM
Promise on Dec 25, 2020 1:06 AM
Dexie on Apr 21, 2020 12:00 AM
PWA on Apr 20, 2020 6:00 PM
G Suite on Apr 01, 2020 12:01 AM
CSS Grid on Mar 01, 2020 3:03 AM
Update your home page on Jan 21, 2020 12:20 AM
Cloud 9 on Nov 22, 2019 9:42 PM
Adobe Sensei on Jan 01, 2019 11:11 AM
Summer time blues on Aug 11, 2018 6:42 PM
Web font test on Jan 01, 2018 11:13 PM
Help desk on Jun 01, 2017 12:00 AM
RWD by HTML5 on Jun 07, 2016 8:28 PM
Big D on Jun 05, 2016 6:45 PM
SN on May 22, 2016 2:09 AM
Ant on Apr 03, 2016 10:01 PM
Windows env tips on Mar 31, 2016 1:44 AM
Cache on Mar 08, 2016 8:06 PM
Detected as bad site by virus company on Mar 08, 2016 1:07 AM
Google API on Feb 14, 2016 1:03 AM
OSS License on Jan 08, 2016 12:00 AM
Bash on Jan 07, 2016 10:41 PM
Regular expression on Jan 06, 2016 1:27 AM
Javascript on Jan 05, 2016 7:27 AM
Laravel on Jan 04, 2016 12:00 AM


June 9, 2021

k8s
全て想像ですが
読み方はケーツと読みます、半端ねーてす、あるいは半端ネース

ケツが扱う最小単位がPodで1つの機能を持つ(Podは1つ以上のコンテナを含む)
ReplicaSetは複数のPodを組み合わせてアプリを実現する
DeploymentはReplicaSetを管理、アップデートの際は新規ReplicaSetを作成してバージョン更新を行う
ServiceはDeploymentに対してIPアドレスやLBを設定してサービス提供する
クラスターはServiceが複数動く環境、1つのMasterと複数のNodeから構成され
 Nodeはコンテナを動かす為のサーバ、MasterはNodeを管理しスケジューリングやオートスケールを行う

Docker
 Immutableインフラ(不変の)でDockerfileの方を変える、Dockerイメージは可搬性をもたらす
 コンテナはOS上に配置する(複数配置できる、Dockerfileさえあれば再現可)
 流れ
  Dockerfile(設定)とアプリをdocker build/pushし
  DockerレジストリにDockerイメージを作成
  GKEにデプロイ(deploymentファイル.yml/serviceファイル.ymlをkubectrl create)
   レプリケーションコントローラ:Pod数、オートスケールをdeployment fileで設定
   サービス定義:ノードのproxyデーモンが複数Podに負荷分散
    ノードがクラスタ内のPod同士に振分けるクラスタIP
    LBが振分ける外部IP、
K8s
 クラスタリング(複数サーバを束ねる)
 コールドスタンバイ、ホットスタンバイ(フェイルオーバ)
 オーケストレーション…NW、Storage、スケジュール、IP、ルーティング、負荷分散、監視、デプロイ
 構成
  etcd(kvs形式のconfig)
  マスターサーバ
  レジストリサーバ(コンテナレジストリ:GCSに保存)
  ノード>Pod>コンテナ(webサーバ)、コンテナ(ログ収集)、仮想NIC
  ノード、ノード…
GKE
 コンソールで設定+kubectrl
  コンソール:GCE、ストレージ、タスクキュー、BQ、cloudSQL、cloudDataStore、cloudソースレポジトリ、StackDriverLogging、StackDriverMonitoring、StackDriverTrace、CloudPlatform、BigTable、Pub/Sub、サービスコントロール、サービス管理

■流れ
 GKEでクラスタを作成
 Kubectrlをインスコ
 KubectlでPodを立ち上げ>Deploymentができる、複数Podの起動も
 Kubectlでサービス公開設定
【GCP入門編・第7回】Google Container Engine (GKE) での Docker イメージの立ち上げ方 | 株式会社トップゲート (topgate.co.jp)

 サービスアカウント作成
 ネームスペース、kubeサービスアカウント作成
 サービスアカウントとKubeサービスアカウント紐づけ(gcloudとbubectlの両方)
 Yamlで機能を宣言しKubectlでデプロイ

Pod(論理ホスト/インスタンスみたいな)
 一意のIPが自動的に割り当てられる
 Pod内のコンテナはlocalhostで互いに通信、コンテナ間で共有するストレージ
 Podを直接作成は非推奨
 CPU/メモリの最小と最大を設定

Workload identityでServiceAccountとケツのサービスアカウントを紐づけ認証
k8sのsecretはPw/Oauthトークン/SSH key等を含むオブジェクト(base64エンコード生)
 使う方法3種類:コンテナにマウント、コンテナの環境変数、Pod生成時にケツがpull
  どこに置くか、どう暗号化するか、gitに置かない等の考慮が必要

=========
 時間の掛かっていた処理をクラスタ構成で並列処理させて早く終わらすとか
VMからOSを抜いてアプリを入れたものがコンテナ、ドッカ―がOS以下を手配
Dockerがコンテナを管理、k8sがそのDockerをオーケストレーション
複数台でまとめたクラスターで故障があっても切り替え可用性を保つ
 そのクラスターをnamespaceで分割し複数チームで利用することも可
稼働中にサーバ追加のスケールをしたりロールバックできる
podにIPを割り振ったり、DNS名を振ったり、負荷分散したり
自動デプロイでコンテナイメージをサーバ群へ展開する
Dockerのホスト管理、コンテナのスケジューリング、ローリングアップデート、死活監視、ログ管理等々
masterとworkerで構成されmaster3台、worker2台~位のサーバ要る
Externalname>LoadBalancer>NodePort>ClusterIP
コンテナにはストレージを置かず外部に持たせた方が良いかも
ユーザ管理も必要
Dockerはイメージという感じか、複数OSを入れられるヤツで、それらを束ね管理するのがケーツ
https://www.kagoya.jp/howto/rentalserver/kubernetes/
https://udemy.benesse.co.jp/development/system/kubernetes.html

=========
↓実際のアプリがないとイメージ沸かん

クイックスタート: 言語に固有のアプリのデプロイ  |  Kubernetes Engine ドキュメント  |  Google Cloud
コンテナ化されたウェブ アプリケーションのデプロイ  |  Kubernetes Engine  |  Google Cloud
Cloud buildを使用してアプリをコンテナイメージにパッケージ化
GKEでクラスタを作成、コンテナイメージをクラスタにデプロイ

PHP のドキュメント  |  Google Cloud
PHP スタートガイド  |  Google Cloud
Firestore でのセッション処理  |  PHP  |  Google Cloud 複数インスタンスのsession管理にはFirestore
PHP でのユーザーの認証  |  Google Cloud IAP(Identity-Aware Proxy)
アプリがPHPならこれを参照

PHP を使用したバックグラウンド処理  |  Google Cloud
 Cloud run(コンテナ化アプリのスケールできる実行、CICDで自動Terraform applyできる?)と
 Pub/Sub(イベントドリブンでメッセージングとデータ取り込み)

=========
↓手始め?
GKEでnginxを外部アクセス可能にするまで - Qiita

=========
GKE

Posted by funa : 12:01 AM | Web | Comment (0) | Trackback (0)


May 21, 2021

GCP Hands Off
データの種類でアーキテクチャを決める
 コンテナはオーバヘッドが少なくVM/GCEに比べ軽量高速、スケールアップ/ダウンに優れている
GCE
 LauncherでアプリをGCEにデプロイ(数クリック)
 永続ディスク…SSDも選択できる
 ローカルSSD…高性能
GCS
 IAPを使うと画像アクセスにも認証が使えそう>LBのバックエンドではIAPが使えない
  GCEにGCSマウントするとGCEのIAPとしてイケる、gcsfuseのOSSでLinux上のドライブになる
   CensOS6.8にgcsfuseをインストールしてGCSをマウント - Qiita
   GCS Fuseを使ってみる - Qiita
 リテンションで保護期間を設定したり、ライフサイクルで削除時期を設定したり
 世代管理ができたり
CloudSQL
 ライブラリSQL APIを有効に
 平文通信→CloudSQL proxyバイナリをVMインスコ
  proxyとアプリ設定を合わせる、proxyサービス起動

■制約が重要そうでまとめて記載したい
 IAPとCDNの両立はできない
 LBのbackendにgcsを設定したときはIAPが使えない

■ハンズオン(GAE:php+FW+IAP)→GAEよりCloud runが良い
IAPはGAEが簡単そう(アクセスするのにGoogleの認証プロンプトを出す)
 自前DNSにTXTレコードを設定>確認>IPが表示されAレコードやCnameも登録でき、SSL証明書も使えるようだ
  しかし無くてもgoogle提供のドメインが使え不要 DNS(TXTレコード)による所有権の確認 - Google Search Consoleの使い方 (howtonote.jp)
 WinローカルにGCP SDKインスコし下記にapp.yamlとindex.phpを置いてcmd→ gcloud app deploy
  C:\Users\おまはんのユッザー名\AppData\Local\Google\Cloud SDK\php
 IAPを有効にしIAM secured userの権限とIAMでGAE viewer権限付与で@gmail.comユーザ等は見れる
  外部ドメインを使うときはIdentityPlatform設定が必要そう
止めるにはinstanceを削除する(再度アクセスでinstanceが自動作成される)、IngressをInternal onlyにすると一応止まるか、楽だ

■ハンズオン(GCE+nginx+FW+LB+IAP+Cloud NAT+Cloud armor)
●cloud shell terminal
gcloud compute instances list インスタンス一覧
●コンソール
GCE VMを作成(Instance scheduleで起動-停止時間が入れられる、テンプレやグループに使えない?)
 instance template作成 ubuntu18、API access scopeには"Allow full access to all Cloud APis"で
  外部からアクセスさせずLB経由だけにしたい→外部IPがephemeralで止められない→作成時にnetwork>external ipをnoneで作成すること→
  外へでれなくなるのでgcloudコマンドが通らない→CloudNATも設定
 instance group作成 あるいは VM instance作成
  IGが中々できないならIGを開きエラーメッセージを見ること
SSHの項目からview gcloud commandで好きなSSHターミナルからアクセスできるcmd出る
 gcloud beta compute ssh --zone "asia-northeaset1-b" "instance-3" --tunnel -through-iap --project "bangboo-sandbox"
●SSHターミナル
gcloud init インスコ
sudo apt-get install nginx Webサーバインスコ、ブラウザで内部IPでアクセスしたかったが不可だった
sudo service nginx stop 止める、動かすのは sudo service nginx start
ps プロセス見る
curl http://10.117.0.19 nginxが動いているか確認
cat /var/log/nginx/access.log ログ確認
●nginx
/etc/nginxにあるconf系が設定ファイル
sites-enabled/default だけがあり cat default しdocument rootは/var/www/htmlと判明
 ここへ移動 cd /var/www/html
sudo cp index.nginx-debian.html index.html コピー
sudo nano index.html で編集
設定変更後は sudo service nginx restart
●コンソール
FW作成
 gceに外部IPがあればアクセス試す
 fw-bangboo-http-ingress-allow ingress - "all instances" - 0.0.0.0/0 デフォルトで許可+ingressが必要
  httpsはIPではダメ、ドメイン/証明書が要るか知らんがhttpでは外部IPあればアクセスできる
   GCPのIPを自前のDNSのAレコードに設定しとけば、、
   ウェブとメールを別々のサーバで運営したい?・・・それ、ゾーン設定で出来ます! | さくらのナレッジ (sakura.ad.jp)
   ドメイン所有はDNSにTXTレコード設定ができるようだが、、、
   ウェブマスター セントラル (google.com)
 fw-bangboo-all-ingress-deny ingress - "all instances" - 0.0.0.0/0 で設定完了まで止めとく
  使うときfw-bangboo-all-ingress-deny ingress - "all instances" - 192.168.1.255/32 に設定?
 外部IP(普通LBとなるか)への制御はCloud armorのでdeny allowしてFWではあんまり考慮しない?
LB作成
 VMインスタンスグループ(子インスタンス)作成(上で作ってなければ)
  インスタンステンプレート作成
 LBヘルスチェック(閾値)が要る
 httpLBだと内部か外部か選択できる
  httpLBならIPレンジが要る>VPC networkで同resionで使われていないものを設定
  例10.55.20.0/22なら10.55.23.255まで使われているので10.55.25から使うとか
  NW計算 ネットワーク計算ツール・CIDR計算ツール | Softel labs
   VPCのサブネット設定は拡大できるが縮小ができない→小さめにしておきたいが、k8sはIP沢山使うので大きめ
   プライベートサービスコネクト(VPC間を繋ぐ)を使うと疎結合でつなげられるが
 backendはhttpで、healthcheckはtcp80とproxy無し
IAP作成
 外部 HTTPS ロードバランサの設定  |  Identity-Aware Proxy  |  Google Cloud
 IAP(https)を見るとFWで開けてくれの指定がある
  fw-bangboo-lb-gce-allow Source IP range:072.72.1.19/22, 69.11.8.0/16 tcp:80
 IAPを見るとLBを設定するとFWはLBに対するものだけになるので不要との指示がある
  fw-bangboo-http-ingress-allow 0.0.0.0/0(削除)
  下記はインスタンス作成時の許可設定分で不要
   default-allow-internal 69.11.0.0/9(削除) default-allow-http 0.0.0.0/0(削除)
   これも不要?default-allow-http 0.0.0.0/0 tcp:443(削除)default-allow-icmp 0.0.0.0/0(削除)
   default-allow-rdp 0.0.0.0/0 tcp:3389(削除)default-allow-ssh 0.0.0.0/0 tcp:22(削除)
 IAP(ssh/tcp)を見るとFWで開けてくれの指定があるが開けるとhttpsに穴ができると出るし止め
  fw-bangboo-lb-iap-tcp-allow  Source IP range:072.72.2.0/20 tcp:all(sshターミナルを使う時だけFW開ける、通常priority9000)
 IAPをONだけでは駄目で、FWで調整してGCEに直接アクセスじゃなくLBでやっとIAPが動くみたい
  IAPの設定でhttp://IPでアクセスするとhttps://に転送されたのだが(IAPがない場合は下記設定をするようだ)
  HTTP(S) 負荷分散用の HTTP から HTTPS へのリダイレクトの設定  |  Google Cloud
事前にgce.bangoo.com -> 117.072.19.255 (LBのIPはephemeralをstaticに変更)を自前のDNSに設定
 (DNSのTTLを前日に3600から300に変更しておいたり、DNS反映期間があったり)
 LBのフロントエンドでマネージド証明書を設定(ssl-policyを緩めで設定したが必要?)
  オレオレ証明書は?
 LBフロントエンドはhttpsでもバックエンドはhttpで
 IAP-secured web app userロールを@gmail.comユーザに付与
 IAPとCDNの両立はできない
 LBのbackendにgcsを設定したときはIAPが使えない→ネット公開にしてVPN SCで制御?、GCEにGCSをマウント?
FW調整
 0.0.0.0/0 all deny priority2000>LB関連 tcp80 allow 1000/IAP関連 tcp allow 1000>(使用拠点のソースIP allow 500)
 GCEの外部IPを止める:インスタンステンプレート作成時に外部IPnoneで設定(StaticIPを買って削除でもnoneにできなさそう)
 必要なもの以外を止める:0-442, 444-65535で443のみ許可は駄目か?
 Connectivity testでテストがIPアドレス等でできる(設定変更から実際の反映に時間が掛かるものがあるような気が)
apache benchでスケールするかテスト Apache Bench を使って初めてのベンチマークテスト - Qiita
 sudo apt install apache2 abはapachに含まれるのでどれかのVMにインスコ
 ab -n 1000 -c 100 https://gcp.bangboo.com/ でインスタンスが増えることが確認できる
Cloud armor設定
 DDoS等を防ぐのでOnでいいのでは、adaptive protectionで優先度低いdeny設定
 外部IPのdeny allowはこれでやれば良さそう
Access context manager設定(+VPC service control)
 Organizationの設定が必要(≒Cloud identityでドメイン必要?)IPアドレスやOS等でアクセスを制限できる
FWでIngress全止め or VMインスタンス停止、LB停止


sute16 asia-northeast1-b 2021/7/24(91日で33000yen-10/20位まで)
Instance groupはどう止める?>LB削除>LBのバックエンド削除>Instance group削除
 LBはinstance groupがいる、IAPはGCEの場合はLBにSSL証明書要る
  DNSのAレコードを登録しLB設定すれば証明書入る
   毎回検証終了時につぶして、立てるのが面倒そうだな→FWでdeny allしとく
 【初心者】GCP Identity-Aware Proxy (IAP), Access Context Managerを使ってみる (WEBサーバへのアクセス制限) - Qiita

nginx+PHP appサーバ+BigQuery+BigTable+CloudSQL(MySQL)+GCS+α?
 [PHP]BigQueryのデータを取得する | yyuuiikk blog
$ composer require google/cloud でインスコ
<?php
require 'vendor/autoload.php';
use Google\Cloud\BigQuery\BigQueryClient;
$keyfile = './credential.json'; //svacのkey
$bigquery = new BigQueryClient([
    'keyFile' => json_decode(file_get_contents($keyfile), true),
]);
$dataset = $bigquery->dataset('dataset-name');
$table = $dataset->table('table-name');
$queryJobConfig = $bigquery->query(
    "SELECT * FROM `project-id.data-set-name.table-name` LIMIT 100"
);
$queryResults = $bigquery->runQuery($queryJobConfig);
foreach ($queryResults as $row) {
    print_r($row);
}
Google Cloud Storage にPHPを使ってファイルをアップロードする | カバの樹 (kabanoki.net)
$composer require google/cloud-storage でインスコ
<?php
require __DIR__ . '/vendor/autoload.php';
use Google\Cloud\Storage\StorageClient;
$projectId = 'bangboo-prj';
$auth_key = './iam/credential.json';
$bucket_name = 'gcs-bangboo';
$path = 'img.png';
$storage = new StorageClient([
   'projectId' => $projectId,
   'keyFile' => json_decode(file_get_contents($auth_key, TRUE), true)
]);
$bucket = $storage->bucket($bucket_name);
$options = [
   'name' => $path
];
$object = $bucket->upload(
   fopen("{$path}", 'r'),
   $options
);
<img src="https://storage.googleapis.com/gcs-bangboo/img.png">
SSLに対応したNGINXリバースプロキシを構築する手順 - Qiita
 nginxは静的コンテンツを高速に配信するように設計されている。 また、 リバースプロキシ の機能を持つため、背後にWebアプリケーションサーバを配置して動的なコンテンツを配信したり、ソフトウェア ロードバランサやHTTPキャッシュとしても使うこともできる。
GCPにセキュアな踏み台サーバーを作成する. GCPのIdentity-Aware… | by Taiga Murakami | google-cloud-jp | Medium
 Googleにバックドアを開けてしまっては危険、、、ということはない


End

Posted by funa : 12:00 AM | Web | Comment (0) | Trackback (0)


May 20, 2021

GCP
■GCP(Google Cloud Platform)
https://console.developers.google.com/
GCPを活用するスキルを問われる「Associate Cloud Engineer」
インフラストラクチャの知識を問われる「Professional Cloud Architect」
データと機械学習の知識を問われる「Professional Data Engineer」
 マシーンラーニング:教師ありをベースにパターンを線形として認識し相似のパターンを見つける
 ディープラーニング:人間が把握できる次元のデータ構造ではない多次元でパターンを見つける
  線形検索みたいなもんか

■GCP
https://techblog.gmo-ap.jp/category/gcp/
https://tech.zeals.co.jp/entry/2019/01/08/094054
https://techblog.gmo-ap.jp/category/tensorflow/

12 か月間300 ドル分だけ無料
https://console.cloud.google.com

無料だとBigQueryのDML(insert)ができないらしい
予算とアラートを1円で設定(通知チャネルにSMSとメール設定)

辞めるときはプロジェクトをシャットダウン&請求先アカウントの閉鎖
1)プロジェクトの閉鎖
Google Cloud Console > IAMと管理 > 設定 > シャットダウン
2)請求先アカウントの閉鎖(原因不明だが下記画面が出るときと出ないときがった)
Google Cloud Console > お支払い > (左ナビ)アカウント管理 > 請求先アカウントの閉鎖
※お支払い>マイプロジェクト>アクション>無効や請求先変更ができる

セキュリティは使用GoogleアカウントのSMSによる2段階認証、信用するデバイスの設定があるようだ

GCP ハンズオンセミナー Google_Cloud_GCPHandson_infra1122.pdf (cloudplatformonline.com)
 GKE, Cloud SQL, Dataflow等
【GCP入門編・第3回】難しくない! Google Compute Engine (GCE) でのインスタンス起動方法! | 株式会社トップゲート (topgate.co.jp)
【GCP入門編・第12回】 BigQuery を使って気軽にビッグデータの解析を行ってみよう! | 株式会社トップゲート (topgate.co.jp)
【GCP入門編・第25回】 Cloud SQL for MySQL で Master-Slave 構成を組もう! | 株式会社トップゲート (topgate.co.jp)
【GCP入門編・第29回】Cloud Load Balancing で Web アプリケーションにロードバランサーを設定する | 株式会社トップゲート (topgate.co.jp)
【初心者】GCP Identity-Aware Proxy (IAP), Access Context Managerを使ってみる (WEBサーバへのアクセス制限) - Qiita

■IAM(Identity and Access Management) 
https://cloud.google.com/iam/docs/overview?hl=ja
https://cloud.google.com/iam?hl=ja
IAMベストプラクティス https://cloud.google.com/iam/docs/using-iam-securely
操作方法 https://cloud.google.com/iam/docs/how-to?hl=ja
ロール https://cloud.google.com/iam/docs/understanding-roles?hl=ja
https://www.isoroot.jp/blog/1244/
https://medium.com/google-cloud-jp/gcp-iam-beginner-b2e1ef7ad9c2

//IAMの機能
機械学習を使ったスマート アクセス制御の最適化
デバイスのセキュリティ、IP アドレス、リソースタイプ、日時などの属性に基づいて、リソースに対するきめ細かいアクセス制御ポリシー
権限の認可、解除、委任に関するすべての監査証跡の履歴
ユーザーとグループのプロビジョニングや管理、シングル サインオンの設定、2 要素認証プロセス(2FA)

//IAMポリシー
IDをGroup(●●部)にアサイン
 Members(Group等)にRoles(●●役)をアサイン
  MembersとはグループやドメインやID(Googleユーザアカウント、サービスアカウント)
 Roles(●●役)にPermissions(権限)を付与

ロールは作成ができ●●世話役みたいな感じか
permissionsは権限で「resourcemanager.projects.get」等でロールに紐づける
 個人や無料アカだと組織がない?→フォルダが作成できない?
 組織がないとグループが作成できない→グループがないとIDにRoleを付与するしか
フォルダは組織ツリー状でリソース管理、組織改編が多いならプロジェクトフォルダでも
 各フォルダに対してそれぞれメールグループを定型(folder-admin/dev/lead/member/parttime/etc)で持たせ
 メールグループへのユーザ出し入れで権限の管理をするのが良さそう
IAMやServceAccountの一覧には出てこないが存在するIDがある、実際に権限を付与できるかで存在確認する(TFで作成の場合?)
ポリシーはMSのGPOみたいものも組み込みで存在する
サービスアカウントはAPI用、人が使うことは基本想定されていない(impersonateできるが
ユーザが削除になっても権限やリソースは残るみたい

メールグループの権限関係の確認方法
 仕組み:祖->親->子、上の権限は下も持つ
 権限から確認する、所属から確認するの両面で確認
 1)権限を持っている全ての子をリストアップ
 2)所属しているメールグループの全ての親をリストアップ

//リソース
階層:Organization > Folders > Project > Resource(Google Cloud services)
割り当て:日や分に対してのデータ量の上限等を設定

必要以上に権限を付与しない
組み込みロールが多い、改変してロールを作るか
権限はサービス名.リソース.動詞という命名規則
プロジェクト名はGCPグローバルで名前空間を共有しており、企業名等でprefixするのがいい
プロジェクト毎にメールグループを設け、権限はメールグループの参加で管理したい

//リージョンとゾーン
リージョン:データセンターの存在場所、ゾーンをいくつか持つ
ゾーン:障害ドメイン区画(単一障害点を避ける形で環境設計したい)
Google Cloud SDKをインストールすればコマンドラインが使える
 BQは同一リージョンでないとJoinができない、ゾーンはマルチで良い

■authorized view 承認済みview(BQ権限)
設定すると権限を元のテーブルにさかのぼり付与しなくてもいい(設定がないと元テーブルにも権限が要る)、被参照テーブルに参照許可するビューを指定する
BigQueryの承認済みビュー設定方法 - Qiita

■GCS
 http(s)で公開可
 Nearline…月1アクセス等
 Coldline…年1アクセス等長期アーカイブ
 (standard以外は最低保存期間の縛りがあり早期削除でもお金が掛かる)
 Multi-regional 99.95%、Regional 99.9%の可用性
料金  |  Cloud Storage  |  Google Cloud
  5GBまで無料、リージョンで値段が違う、保存/NW/取得/操作で課金
  nearlineの保存は半額で取得と併せstandardと同じ金額になるが操作費高い
   月1未満ならnearline
  coldline/archive storageは年1程度とされているが使うと結構お金が掛かる
   長期保存はせずできれば削除する、できないならポリシーでcold/archiveへ移動
    最低保存期間の縛り(90/365)があり早期削除でも請求、その期間は置いておく

■GCP Cloud asset inventory
 5週間分の履歴が保管される
 CAI exportにより任意のタイムスタンプでBQあるいはGCSに履歴情報を吐き出す
 gcloud CLIのgcould asset search-all-resourseコマンドにより設定
  BQに吐き出し各種状況のチェックやポリシーのチェックに活用

■Cloud logging
 毎月取込50GBまで無料、取込0.5$/GB+保存0.01$/GB、2種類ありAuditLogで有効無効化
  管理アクティビティログ 13ヵ月400日デフォ有効(_requiredログバケットは取込もデフォ期間保存も完全無料)
  データアクセスログ デフォ無効(有効にしてもデフォ保存期間30日は無料、50GBを超える取込が有料)
   ※つまり50GBを超えた取込、あるいは保存期間を伸ばした分が有料
 BQ streaming insert0.05$/GB+BQ保存(10G無料)0.02/GB=0.07$/GBでBQ化し保存が得
  長期保存が必要なものだけエクスポート
  集約エクスポート
  ログ取集前にログシンク(取込費がかからない)
   サンプル1%等で絞る等

■他
///gcloudをプロキシで使う環境設定とか
https://qiita.com/tora470/items/bc00bef8cba9f9acecc7

///サービスアカウントで認証
Google Cloud SDKのインストールと認証の設定について - TASK NOTES (task-notes.com)
秘密鍵さえあれば成り済ませる
 ※サービスアカウントはサービスを有効化したときに動作用に自動作成されたり、別途手動でも作れる

サービスアカウントのキーを作成しローカルに保存
SSHでGCEのVMに内容をコピペしてキーファイルを作成
下記でSAとしてログイン
gcloud auth activate-service-account ketsu@un.com --key-file /home/ketsu/sakey.json
cloud shell terminalでもファイルをアップロードできるのでup後下記でOK
gcloud auth activate-service-account ketsu@un.com --key-file sakey.json
ログオン切替
終わるとき rm sakey.json

shellセッションごとに環境変数でkeyを設定する方法も
認証のスタートガイド  |  Google Cloud

/// サービスアカウントキーを発行せずにサービスアカウント権限を使う
サービスアカウントに使いたいロールを付与(roles/accesscontextmanager.policyAdminとか)
自身にroles/iam.serviceAccountTokenCreatorを付与
叩く gcloud projects get-iam-policy project-id-xxxxx --impersonate-service-account
 ※tfだとproviderにimpersonate_service_accountを追加する形

///Loadbalancer
 IAPはhttp LB/GCE/AppEngineに
 Internal LBにExternal IPは無理

ついでにIAP tunnel userの権限で踏み台が作れる+OS Loginで認証強化
 OS LoginはIAPの認証機能でSSH上でGCEインスタンスにログインできる代物
 GCPがSSH keyとIAMをGCEに準備してくれる

ついでにリバースプロキシ(nginxとかで作る)
LBみたいなもんだがプロキシでキャッシュを返す
代理代表サーバとなりWEBサーバ界のFWみたいな役割もできる

///NoSQL
=not only sql、分散kvsだったりの非構造化データ、下記2つのみ提供
 キーを指定してCRUD(追加、取得、更新、削除)
 キーの範囲かキーの前方一致でのスキャン

///bigtable
高スループット低レイテンシー読み書き速く膨大なユーザや数千万件テラ以上で
gmail、GA、マップ等々で使われている

///cloud functions
サーバレスでRESTみたいな形でURLでサーバアプリを実行、Node.js/PHP/Python等のコードが直接コンソールに掛ける
 ブラウザでcloud functionsにアクセスしたら下記が出た
Error: Forbidden Your client does not have permission to get URL/kuso-ketsu from this server
呼び出しの認証  |  Google Cloud Functions に関するドキュメント
curl https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME  -H "Authorization: bearer $(gcloud auth print-identity-token)"
↑curlでいいなら、コンソールで[未認証の呼び出しを許可する] 設定 + allusersでも可

///Pub/Sub
パプリッシャーからサブスクライバーにメッセージ転送、順序設定可、大量データを1件ずつとか
publisher -> topic : メッセージ -> push型 subscriber -> cloud scheduler
publisher -> topic : メッセージ -> pull型 subscriber -> cloud functions/run

BQ テーブルにデータをエクスポートする Dataflow ジョブ
GCS でデータをテキスト ファイルまたは Avro ファイルにエクスポートするための Dataflow ジョブ

///BQ job エラー
bq show -j <job-id>
クエリならjob/query historyでわかるがbq cmdでもエラーが返る
bq query --nouse_legacy_sql 'select ketsu from `prj`.oshi.ri'
 unrecognized name: 'kusofuke@ketsu.com' at [1:149]

///シリアルコンソール接続
SSH接続できない!そんな時のシリアルコンソール | apps-gcp.com
突然起動しなくなったWordPressサーバーをなんとか復旧した話 | (tipstock.net)

///gcloud cmd
gcloud organization list GCP IDやGoogleWorkspace IDが分かる

///Recommender
API の使用 - 推奨事項  |  Recommender のドキュメント  |  Google Cloud

///Googleスプレッドシート+GAS+BigQuery
GAS:マクロで記録してそれを使いまわす
 GASでBQの制御は難しいかも、更新してもBQのデータが古いままだったりする(appscript.jsonに権限を追記しても)
 データを一時でも書込ならスプレッドシートの共有の編集権限とシート保護しない設定が必要と思われ(セキュリティがザルに)
呼び名
 connected sheetでBQのデータをスプシに抽出する
 federated queryはBQに外部ソース(スプシ等)をインポートする

スプシの保護(シートはコピーできザルなのでセキュリティ対策でなくデータ保護)
シートを保護する、非表示にする、編集する - パソコン - ドキュメント エディタ ヘルプ (google.com)
スプシの閲覧共有だけでBQコネクテッドシートのプレビュー/抽出は可能だが、それをvlookup系で他のセルに移せない
組織でコネクテッド シートを使用する - Google Workspace 管理者 ヘルプ
他のブックにすればいいかも
編集共有した別ブックに入力データ(日付やメール)を持たせBQフェデレテッドクエリでBQに準備
閲覧共有した別ブックは参照用にBQコネクテッドシートがある形

GASでAdminDirectoryを使う
 gas > サービス > AdminDirectory APIをOn
 gcp該当prj > APIダッシュボード > ライブラリ > Admin SDKを有効
 等でg workspaceのユーザ情報が取れるらしい
  Google Apps Script試行錯誤 Blog: AdminDirectoryでUsers.listを取得したい (pre-practice.net)
  GASでAdmin SDKを利用する(Directory編)その1 - Qiita

///セック
セキュアなBigQueryの運用方法 - Speaker Deck
 IAM condition: 20時以降はアクセスできない等時間やリソースで権限制御
 VPC-ServiceControls: VPC+FWで制限を掛けられなかったがIPやIDで制限を掛ける(クレデンシャル漏洩防御)
  LBのバックエンドをGCSにするとIAPが使えない時も
  TF)perimeterで境界を設定してaccess leveで超えれるものを定義
   危険で user explicit dry run spec = trueでテストしながら falseで本番化
   statusが本番用、specがドライラン用で一旦statusを消してテスト
    restricted_services = storage.googleapis.com ならGCS
    resource
    access_level
  https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter
GCPでセキュリティガードレールを作るための方法と推しテク - Speaker Deck
 サブネット作成の際はセキュリティの観点からフローログを15分で取る
 監査ログを有効に
 ContainerResistryの脆弱性スキャンを有効に
 ログ:データアクセス/ポリシー拒否は30日、管理アクティビティは400日
  BQにバックアップしたい
 SecurityCommandCenterで脆弱性を検知
Cloud Audit Logging 活用のベスト プラクティス | Google Cloud Blog
 集約エクスポート シンクにより監査ログをBQに貯めたい

■アプリ
公開資料 - App Modernization OnAir 〜 モダンなアプリケーション開発とは 〜 (cloudonair.withgoogle.com)
cloud runの設定だけでCDCIできる(第10回

●外部IP
External IP addressで取得、300円/月位、通常一つは自動で割り当てられる

●PoP(Point of presence)
 世界70か所でGCPとエッジ(ネット)接続

End

Posted by funa : 09:00 PM | Web | Comment (0) | Trackback (0)


May 2, 2021

Terrafirma
公式
https://www.terraform.io/docs/index.html
導入
https://www.terraform.io/guides/core-workflow.html
推奨方法
https://www.terraform.io/docs/cloud/guides/recommended-practices/index.html
 https://www.terraform.io/docs/cloud/guides/recommended-practices/part1.html
 https://www.terraform.io/docs/cloud/guides/recommended-practices/part2.html
 https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.html
 https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.1.html
 https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.2.html
 https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.3.html
 https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.4.html
チュートリアル
https://learn.hashicorp.com/collections/terraform/gcp-get-started
HCL
https://www.terraform.io/docs/language/index.html
CLI aka cmd(アルファベットリストから使う)
https://www.terraform.io/docs/cli/auth/index.html
GCP用リファレンス
https://registry.terraform.io/providers/hashicorp/google/latest/docs

お便強
https://qiita.com/minamijoyo/items/1f57c62bed781ab8f4d7
https://qiita.com/donko_/items/6289bb31fecfce2cda79
https://www.apps-gcp.com/infra-automation-01/
https://colsis.jp/blog/gcpterraform/

Infra as codeとしてインフラの構築や設定をコード化できる
特にクラウドだと構築の自動化や構成管理等でのレバレッジが強力

■段階
Terraformとは?基本知識とTerraformのメリット4つを紹介 | テックマガジン from FEnetインフラ
必要なリソースをTerraform化>workspaceの活用>main.tfの共通部分をmodule化

moduleは構成に合わないようなリファクタリングが必要になった時にterraform state mv が必要になってとたんにつらい、moduleを細分化しすぎるとvariable と output が大量に必要になって書きづらい、moduleは再利用できる複数のリソースの単位(プログラミング言語でいうところの関数みたいなもの)で作るのがしっくり

リソースの差分を無視するlifecycleブロックを使う
resource "aws_autoscaling_group" "app_1" {
  name = "app-asg-1"
  lifecycle {
    ignore_changes = ["load_balancers"]
    create_before_destroy = true//新しいのを作ってから古いのを削除
  }
}
外部ファイルを文字列として読み込む
resource "aws_iam_role" "ec2_role" {
  name = "ec2-role"
  assume_role_policy = "${file("./ec2_assume_role_policy.json")}"
}
1つのディレクトリで複数のStateを扱うWorkspaceという機能もあるのですが、
個人的には普通にディレクトリを分けて管理する方が楽
production/stagingが完全に同じリソース構成で、設定のパラメータの差分がちょっとだけあるという理想的な世界ではWorkspaceでも運用できるかもしれませんが、現実的にはstagingだけリリース前の検証用の一時的なリソースが立ってたりとか、完全に同じ構成にならないことも多いので、モジュールの読み込みの有無や一部の環境だけ存在するリソースなどの差分を吸収できる場所があったほうが都合がよい

Terraform職人再入門2020 - Qiita
モジュールが公式から提供されている
Browse Modules | Terraform Registry

Terraform の terraform.tfvars とは | 30歳未経験からのITエンジニア (se-from30.com)
環境情報は外部ファイルが基本
prd/stg/dev環境はprd.tfvars, stg.tfvars, dev.tfvarsを用意
.tfvars 各環境の設定
aws_access_key    = "XXXXXXXXXXXXXXXXXXXX"
aws_secret_key    = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
aws_region        = "eu-west-1"
main.tf
terraform {
  required_version = "= 0.12.26"
}
provider "aws" {
  version    = "2.66.0"
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
  region     = var.aws_region
}
var.tf 空の受け皿
variable aws_access_key {}
variable aws_secret_key {}
variable aws_region {}

Terraform で変数を使う - Qiita
実行時に-var-fileで値ファイルを指定して環境などを切り替えると良いかもしれない
terrafrom plan -var-file=dev.tfvars
terrafrom plan -var-file=prod.tfvars
変数ファイル指定がないときは変数でdefaultに入れておく、descriptionで変数の説明もかける
variable "foo" {
  type = "string"
  default = "default-var"
  description = "Sample Variable"
}

credentials等の秘匿したい変数を外部のファイルやコマンドライン引数から読み込む
variable "credentials_file" {} @var.tf 変数を定義し空にしておく
credentials = file(var.credentials_file) @main.tf ファイルを読むがファイル名は変数
terraform plan -var 'project=<PROJECT_ID>' -var 'credentials_file=<NAME>.json' @cmd プロジェクトとクレデンをコマンド時に指定
他にもvars.tfvars設定ファイル(行頭variableが不要)、TF_VAR_環境変数による指定

-var-fileで変数ファイルを明示してcmd、ファイル名は.tfvars/.tfvars.json
-varで変数を明示してcmd
順序があり後の読込でオーバーライド


workspaceは使わない、moduleを限定的に使う
設定をコード化>Gitレポジトリに置く>設定内容、作業履歴の明確化、チームでの運用性向上

■特性(tf import)
TFの影響を反映するのはterraform applyの時だけ、tfファイルとtfstateの差分を実際にリソース作成する
importはtfファイルからtfstateへ記載だけを行う
 カレントdirの全.tfファイルor.tf.jsonを評価するのでtfファイルの名は何でもいい
各リソースに対してTF化するかは選択ができるが、TFする場合はそのリソースに必要な全記載をTFファイルに行う
terraform import tfResourceID.yourResourceName gcpIdentifier のコマンド
 terrafrom import google_bigquery_dataset.tf-1 bangboo-prj/test-dataset
 tfResourceID(リソースIDというようタイプ:リソース種別)はTF指定のもの、yourResourceName (リソース名)は任意のもの
 構成ファイル.tfはローカルのものが使われる、importするとtfstateに反映
 GCP identifierはTF公式サイトの各サービスの一番下import項目を見ると指定内容が分かるのでGCPを見て拾ってくる
 terraform state list TF化されているリソースを見る
 terrarorm apply時にもtfstateは更新される(オプション-refresh=falseで無効可)
  またapply時に-target=xxxでデプロイするリソースを特定できる

Syntax - Configuration Language - Terraform by HashiCorp コメントは#が基本、//や/**/も使える
Terraform v0.12で変わるHCLの記述について - Qiita localsや変数、リストやマップ等
Terraform職人再入門2020 - Qiita yamldecodeやjsonencode等
Terraformの基本 - Foreverly (hatenablog.com)
変数
 variable(input var)はcmd実行時に変数を上書きできるが、localsはできない
 outputはapply時にterminalで値が確認できる、moduleから値を取得する

google_bigquery_connection | Resources | hashicorp/google | Terraform Registry
ドット繋ぎで値を扱える
resource "google_sql_database_instance" "instance" {
    provider         = google-beta
    name             = "my-database-instance"
}
resource "google_sql_database" "db" {
    instance = google_sql_database_instance.instance.name
    name     = "db"
}

ToSetは値設定をするが順不同で重複を省く
resource "xxx" "aaa" {
    for_each = toset(["foo", "bar", "bar"]) でbar, foo
    name = each.key
}

for_each/eachのループ
locals {
    sg = {
        foo = "FOO"
        bar = "BAR"
    }
}
resource "xxx" "aaa" {
    for_each = local.sg
    name = each.key
    description = each.value
}

terraform importはリソース単位、更新はできず削除してから追加 terraform state rm google_bigquery_dataset.tf-1 bangboo-prj/test-dataset
 実設定とimportの内容が違う場合は実設定の情報でtfstate化されるようだ(importは項目を入れ込む感じ?)
  なので実環境に変更を加えるにはterrafrom apply、tfstate化もされtfファイル/tfstate/実設定の3者で同じになる
 apply時にtfstateと実設定が違う場合、例えば既存設定がある場合は重複エラーになりapplyできず、importしtfstateと実設定を同じにしてから、tfファイルの内容をapplyすることが必要

for_eachで書いた.tfをterraform importする | DevelopersIO (classmethod.jp)
 ユーザ指定は user:aaa@xxx.com だったりメールグループなら group:aaa@xxx.com

■既存リソースのTF化のおおよその作業
 作業ディレクトリの作成(プロジェクトに対するローカルのフォルダ)
 プロバイダを指定したtfファイルの作成(gcsにstateを置く設定が良い
  provider "google" {
    project = "bangboo-kuso"
  }
  terraform {
    backend "gcs" {
      bucket = "bangboo-kuso-terraform"
    }
  }
 terraform init ローカルに対して初期化
 リソースタイプと名前を定義したtfファイルを作成する(任意のリソース名、基本ユニーク、纏められるものは重複してもいい)
  resource "google_cloudfunctions_function" "fuckin" { ... をtfファイルに記載
   tfResourceID(リソースIDというようタイプ:リソース種別)とyourResourceName (リソース名) だけで
 リソースタイプや個別パラメータは公式ドキュメントを参照しながら定義
 https://registry.terraform.io/providers/hashicorp/google/latest/docs
  (簡単)tfファイル内で1行目以外は空で、terraform planをするとエラーで必要なものが分かるので、それを埋める
  planが通ると自動的に値をサーバから拾ってくる(importすればtfstate.tfに入っている or コピーしてTFに入れる)
  ※terraform state show tfResourceID.yourResourceName でstateを見てtfファイルにパラメータを定義していく方法もある
  TF定義は複数の方法がある、最終GCP公式のRestAPIで確認するしか
 terraform importする(公式ドキュメントの一番下にimportコマンドの指定がある)
 terraform planして差分がなくなるまでtfファイルを修正する
  import(tfstate)の修正は一度stateから削除する terraform state rm google_bigquery_dataset.tf-1
  (既存リソースがあってもあくまでtfファイルとtfstateの差分なのでinitした状態でplanしてもup-to-dateと表示されるだけ)
 tfstateファイルにおかしなものが無いか確認、keyとか含まれないか

■TF公式ドキュメント
google_organization_iam_custom_role | Resources | hashicorp/google | Terraform Registry
google_organization_iam | Resources | hashicorp/google | Terraform Registry
カスタムロールを設定して、組織レベルのIAMでそれを使いたい
 TFのorg_iamページのArgument referenceのrole項目を見ると
  Note that custom roles must be of the format organizations/{{org_id}}/roles/{{role_id}}
 TFのorg_iam_custom_roleページのAttributes  referenceのrole項目を見ると
  id - an identifier for the resource with the format organizations/{{org_id}}/roles/{{role_id}}
 で下記と分かる、使用側と被使用側のTFマニュアルを両方確認する
resource "google_organization_iam_custom_role" "my-custom-role" {
  role_id     = "myCustomRole"
  org_id      = "123456789"
  title       = "My Custom Role"
  description = "A description"
  permissions = ["iam.roles.list", "iam.roles.create", "iam.roles.delete"]
}
resource "google_organization_iam_member" "my-organization" {
  org_id  = "123456789"
  role    = google_organization_iam_custom_role.my-custom-role.id
  member  = "user:jane@example.com"
}

resourceの2番目リソース名を定義しますが任意の名前を指定します
 ここが同じ項目はユニーク制限がない場合は追加としてまとめられます
 通常はユニークにしterraformで管理するリソース名(yourResourceName)を宣言します
  ※1番目のリソースタイプ内でユニークにするのが基本(全体でもユニークの方が分かり易い)

TFファイルに定義をしたい →定義したいリソースのArgument referenceの項目を設定
TFファイルに定義した内容を変数で使いたい →使いたいリソースのAttributes referenceを見る
terraform importしたい →インポしたいリソースのページ一番下のimportコマンドの指定を見る

■他に一般的なTF(既存がimportされると以下で変更をapplyして運用)
 terraform -v 稼働確認
 terraform fmt ファイルの記述フォーマットを整える
 terraform validate ファイルの検証
 terraform plan アクションを計画
 terraform apply 最後に変更を適応
 terraform show ステータスを確認、一覧
 terraform destroy で簡単にインフラの吐き、initができないとき必要そう

■特定のリソースだけ適応したい
 terraform plan -target="tfResourceID.yourResourceName"
 terraform apply -target="tfResourceID.yourResourceName"

■TFのcount
数を指定してその個数のリソースを作る。なのだが
 enable_lien = true モジュール側/変数側でこう設定し
 count = var.enable_lien ? 1 : 0 リソース側で3項演算子を使えばIFのように使える
  ※for loopのようなインクリのcount"+="でなく"="の1発実行なので3項演算子でIFになる

■tfenvを使う場合
cd my-repo
get clone https://bitbucket/bangboo-prj.git
cd bangboo-prj
tfenv use 0.14.7
 terraform workspace list
 terraform workspace select default デフォルト
  terraform workspace new prod prodという名で作成なら
main.tf作成し記載
 terraform fmt tfファイルのフォーマット(書式は適当で書けばいい)
  gcloud auth list 認証確認
  gcloud auth application-default login クレデンシャルが必要なら
   API&Servicesでクレデンシャルは取得できそう、key=xxxx
terraform init
テラフォーマで既存のリソースを調査するには
terraformer import google list --projects=xxxx-123 で対象のリソース確認
terraformer import google --resources=instances,forwardingRules --regions=us-west1 --projects=xxxx-123 とか
terrafrom import google_storage_bucket.pri-bucket project-abc123/asia-northeast1/pri-bucket でimportとか
 terraform refresh tfstateの最新化、どのタイミングで使う?

既存リソースimport
https://www.apps-gcp.com/terraformit-gcp/
https://qiita.com/uu4k/items/48d3ecfefe57dba1d7e1

■Terraform applyで意図しない権限削除で障害が発生する
Terraform x GCP で、IAM権限を全削除してしまった - Qiita
resource "google_project_iam_policy" "unko" {
  project = "my-project"
  role = "roles/noguso"
  members = [
    "serviceAccount:${google_service_account.baka.email}"
  ]
}
google_project_iam_policy:書き換えるので他は無くなる(他を消したいときに使う)
google_project_iam_binding:付与、Authritativeだが他は現状維持?
google_project_iam_member:付与、Non-authoritativeで安全、まとめ難いか
 ※_iam_policyと_iam_bindingとt_iam_memberは一緒に使えない
 ※_iam_bindingと_iam_memberは一緒に使える

google_bigquery_dataset_iam_binding:(承認済みビューの権限はなくなる>google_bigquery_dataset_accessを使え)
google_bigquery_dataset_iam_member:roleとmemberを1対1でresourceを作りまくる、Non-authoritative
 ※_iam_policyや_bindingはまとめ易そうだが権限消しそう

Terraform で GCP のサービスアカウントを管理する - Eng (なりたい) (hatenablog.com)
Terraform で GCP IAM 設定どれ使うのがいいのか - pokutuna (scrapbox.io)
google_project_iam | Resources | hashicorp/google | Terraform Registry
Authoritative: TFに明示していないものをApply時に削除しますという意、TFの権威
Non-authoritative: TFは権威を示さず、TFに明示していないものは現状維持ですという意

■勝手に公開
terraform vpc auto_create_subnetworks = falseにせなサブネットを公開して作りよる

■Applyの依存関係はdepends_on(プロジェクト作成の前に権限を付与しようとしてエラー等の順序)
[Terraform]Module間の値の受け渡しについて | DevelopersIO (classmethod.jp)
 これより先にあれをTFしてくれという記述

■データセット
google_bigquery_dataset | Resources | hashicorp/google | Terraform Registry
スキーマ取得: bq show --schema --format=prettyjson bangboo-prj:test-dataset.tbl001
ビューはコンソール>BQ>該当ビュー>detailからコピー

■組織ポリシー
google_organization_policy | Resources | hashicorp/google | Terraform Registry
制約について  |  Resource Manager のドキュメント  |  Google Cloud

■テスト
TF Apply後には検証をしっかりしたい、最低Apply後にPlanを再実行したい、テストスクリプト的にチェックしたい
適応されていないことや、TF定義とtfstateと実設定の差分が想定と違うことがある感じがするからだ
moduleを含めて条件的な書き方だと、適応の順序の関係で適応が抜け2回以上TF applyしないといけなかったり

■gcloud cmd
https://www.devsamurai.com/ja/gcp-terraform-101/
 gcloud projects list 権限あるプロジェクトを表示
 gcloud config set project [prjID] ワーキングプロジェクトの設定
 gcloud services enable iam.googleapis.com サービスの有効化
 gcloud iam service-accounts create terraform-serviceaccount \
  --display-name "Account for Terraform" サービスアカウント作成
 gcloud projects add-iam-policy-binding [PROJECT_ID]
  --member serviceAccount:terraform-serviceaccount@[PROJECT_ID].iam.gserviceaccount.com --role roles/editor 権限付与
 gcloud iam service-accounts keys create path_to_save/account.json
  --iam-account terraform-serviceaccount@[PROJECT_ID].iam.gserviceaccount.com クレデン発行
 export GOOGLE_CLOUD_KEYFILE_JSON=path_to/account.json クレデン設定
↑サービスアカウントで認証 環境変数にファイルパスを渡す
 gcloud auth application-default login だと個人
 これにクレデンシャルファイルのパスを渡すとサービスアカウントでgcloudコマンド打てるはず

Terraformで複数リージョンをまたいだリソース制御する (mosuke.tech)
Terraform workspaceを利用して環境毎のリソース名の変更を行う (mosuke.tech)


End

Posted by funa : 10:14 PM | Web | Comment (0) | Trackback (0)


February 21, 2021

BigQuery
■Big queryリファレンス
標準SQLとレガシーSQLがある、違いは?
標準 SQL のクエリ構文  |  BigQuery  |  Google Cloud
標準 SQL への移行  |  BigQuery  |  Google Cloud
標準 SQL のデータ型  |  BigQuery  |  Google Cloud
レガシー SQL 関数と演算子  |  BigQuery  |  Google Cloud
レガシー SQL のデータ型  |  BigQuery  |  Google Cloud
BigQuery: クラウド データ ウェアハウス  |  Google Cloud(チュートリアルみたいな) 

BigQuery解説:https://beyondjapan.com/blog/2016/03/what-is-bigquery/
クエリ処理のツリーアーキテクチャによる分散並列処理
複数のサーバーに対してツリー状に拡がっていき、並列にサーバー上で同時に分散処理
 ルートサーバ>intermediateサーバ>leafサーバ
BigQuery MLという機能を利用すると、機械学習モデルをCloud AI PlatformのTensorFlowなどに連携させ、クエリ結果を素早くAIと連携
Lookerというデータ分析プラットフォームとの連携よりクエリ結果を、データ統合、変換、分析、可視化、レポーティングすることができ、非常に強力なBI

列指向型・カラム型データベース・カラムナストレージ(一般的なRDBMSでは行単位でデータが保存)
 必要なカラムのデータを取得するだけでよく、またデータは圧縮できる
https://dev.classmethod.jp/articles/google-bigquery-debut/

GCPプロジェクト>データセット>テーブル(行row列columnで普通のテーブル、ネイティブbigqueryテーブル/Googleドライブのような外部テーブル、SQLクエリによるビュー)
ジョブは非同期で実行され、ステータスをポーリング(データの読み込み、データのエクスポート、データのクエリ、データのコピーなど)

クエリ(ウェブ UI、bq コマンド、BigQuery REST APIの方法がある、SQLと同じ?
SELECT   title, answer_count, view_count
 FROM  `bigquery-public-data.stackoverflow.posts_questions`
 ORDER BY  view_count DESC LIMIT 10
BigQueryはSELECT tag, time FROM [dataset_name.table_name_20151206]のように必要な列だけを選択した場合にはスキャンの幅を狭めることは可能ですが、LIMITやWHERE句には何を書いてもテーブルをフルスキャンしてしまう
節約 Amaのs3に入れRedshift内でテーブルを分割した後にBigQuery

Hadoopでも使われていたGoogle開発のエンジンであるMapReduceは、非構造化データをプログラミングモデルを通して扱うが、巨大なテーブルの結合や巨大な出力結果のエクスポートも可能である半面、処理時間は数分間から数日に及んだ、だが、BigQueryは、あらかじめデータを構造化してBigQueryのテーブルに格納しておかねばならないが、ほとんどのクエリは数秒で完了する

サードパーティ ツール(データの読み込みや視覚化を行うツールなど)を使用して BigQuery のデータにアクセス可
Google Cloud SDKをインストールすればコマンドラインが使える
BQは同一リージョンでないとJoinができない、ゾーンはマルチで良い

パブリックデータに直でアクセスできる
SELECT * FROM `bigquery-public-data.usa_names.usa_1910_2013`
BigQuery の一般公開データセット  |  Google Cloud
 →FROM句の書き方:他のプロジェクトを指す名前にハイフンがあるとバッククォートで囲む必要がある
  `other-prj`.dataset.table あるいは `other-prj.dataset.table`

■標準SQL
先頭行でレガシーか宣言 #standardSQL あるいは #legacySQL
バッククォートでエスケープ、プロジェクト区切りも.(ドット)、From句のカンマはCross joinで全組合せかと思われ通常通りjoinやunionを使う事
配列が使える、カラム一つに配列を入れて多元的に扱える
withで一時テーブルを作れる
exceptでカラムを除外、replaceでカラムの置き換え
分析関数over()とwindowで計算ができる
 rank() over (order by x)は下記moreのRFMに使用している
地理関数とかJSON関数とか色々関数もありそう
スクリプトで変数やIfやLoopが使える 標準 SQL のスクリプト  |  BigQuery  |  Google Cloud

■レガシーSQL(標準SQLを使うのが由)
予約語は角かっこを使ってエスケープ、プロジェクト区切りは:
集計関数で WITHIN キーワードを使用すると、レコード内の繰り返しの値が集計?
FROM句のカンマは標準SQLのCross joinとは異なりUNION ALL 演算子
通常のSQL処理システムとは異なり、BigQueryは繰り返しデータの処理を前提として設計。繰り返しレコードの構造を操作するクエリを記述。その方法の1つが、FLATTEN 演算子?
JOINは、INNER、[FULL|RIGHT|LEFT] OUTER、および CROSS JOIN 演算子をサポート、デフォルトINNER
除外できる select + from A OMIT RECORD IF COUNT(payload.pages.page_name) <= 80;
TOP を使用するには、SELECT 句に COUNT(*) を含める
分析関数over()とwindowで計算ができる?(標準SQLと同様?)
functionを作って使える(標準SQLと同様?)
JSON等のネストをフラット化

■DDL データ定義言語ステートメントの使用  |  BigQuery  |  Google Cloud
https://www.isoroot.jp/blog/1651/
auto_incrementもdefaultもprimary keyもindexもshow create tableないのでは?
CREATE TABLE IF NOT EXISTS bangboo_data.x_xxx (
  `no` INT64 NOT NULL,
  `user_no` INT64 NOT NULL,
  `name` STRING,
  `date` DATETIME,
)

■bqコマンドはコンソールで実行できる
ブラウザで該当プロジェクトに入りコンソールボタン、下記ではスキーマをJSONで取得できる
bq show --schema --format=prettyjson myProject:myDataset.tbl001

■データアップロード時のスキーマ指定
自動検出はFirestore、Datastore、Avro、Parquet、ORCだけ?ほぼ手動のutf-8のcsvかjsonlかを使う形
コンソールで手動スキーマ指定可(jsonスキーマを張付ける)、modeは省略可でデフォはnullable、
JSONスキーマファイルupはaqコマンドのみ可、ローカルからup時のコマンドとスキーマ例↓
bq load --source_format=CSV mydataset.mytable ./myfile.csv ./myschema.json
[
  {
    "description": "quarter",
    "mode": "REQUIRED",
    "name": "qtr",
    "type": "STRING"
  },
  {
    "description": "total sales",
    "mode": "NULLABLE",
    "name": "sales",
    "type": "FLOAT"
  }
]
なお一旦Google Cloud Storageに放り込んでからやると高速 BigQueryにデータをバッチでインポートする - Qiita

COUNT DISTINCTだが、BigQueryでは概算値が返ってくる??。正確な値が必要な場合は、GROUP EACH BYとCOUNT(*)を組み合わせる
https://www.buildinsider.net/web/bigquery/01

■BQはUTC
ScheduledQueryを終了日6/9 13:00JSTで即時設定→6/9 01:20UTCで実行された
(終了時間にJST/UTCの考慮が必要か→SQ実行時間設定についてはJSTかUTCに注意するだけ)
実行履歴はUTCのためJSTに読み替える必要がある(UTCはJSTの-9時間)

■BigQuery機能
///クエリ結果を別テーブルに書き込む
その他>クエリの設定>クエリ結果の宛先テーブルを設定する
BigQueryではSELECT結果を他テーブルにInsert / テーブル洗い替えなどができる - コード日進月歩 (hateblo.jp)
クエリ結果の書き込み  |  BigQuery  |  Google Cloud

///Federated Query
スプレッドシートやGCSの外部ソースをBigQueryで
範囲の書き方:シート1!A1:B100
Auto detectにするとHeader skipを1にして1行目をカラム名として使うといい
注意)
 シートで構成を変えると滅茶苦茶になる
 空欄のセルはnullになる
 使う人はBQへもスプレッドシートへも両方権限が必要

///パラメータ(変数)を使う
--parameter=min_count:INT64:250
SELECT word FROM `prj.ds.t` WHERE AND count >= @min_count
パラメータ化されたクエリの実行  |  BigQuery  |  Google Cloud

こういう感じでも使えるのでは
WITH params AS (
 SELECT @sheetInput AS p
),
tmp_pre_processed_src AS (
 SELECT * FROM src
)
SELECT * FROM tmp_pre_processed_src
,params
WHERE
 tmp_pre_processed_src.a = p

///*を受ける_TABLE_SUFFIXを使う(複数テーブルだとunion allになる)
SELECT year FROM `bigquery-public-data.ds.gsod19*`
WHERE _TABLE_SUFFIX BETWEEN '29' and '35'
ワイルドカード テーブルを使用した複数テーブルに対するクエリ  |  BigQuery  |  Google Cloud
 BTWで絞らないと全結合で課金が厳しいかも

///時間のパラメータを使う
select * from mytable_{run_time-1h|"%Y%m%d"}
実行時間run_time(UTC)から1時間引いた日→mytable_20180214
クエリのスケジューリング  |  BigQuery  |  Google Cloud

///動的にテーブル名を指定してcreate table
パラメータや変数や_TABLE_FUFFIXだけでは難しい。変数はテーブル名とは解釈されない、_table_fuffixはselect分のfrom句に入れwhere句で内容を指定するがcreate分は無理、execute immediateを用いる
DECLARE t STRING;
SET t = (SELECT CONCAT('x_emp_at', FORMAT_DATE("%Y%m%d", DATE_ADD(CURRENT_DATE(), INTERVAL 1 DAY))));
EXECUTE IMMEDIATE format('CREATE OR REPLACE TABLE `%s` AS SELECT * FROM `prj.bangboo_data.x_employee`', t);

ScheduledQueryでは出力テーブルの指定が可能でテーブル指定例:table001_{run_time-1h|"%Y%m%d"}でOK、なおSQL内にはrun_timeが使用できない

///既存のテーブルをコピー(CREATE OR REPLACE TABLEもあり)
CREATE TABLE IF NOT EXISTS bangboo_data.x_employee_copy (
  `no` INT64 NOT NULL,
  `name` STRING,
) as
select * from `prj.bangboo_data.x_employee`
データ定義言語ステートメントの使用  |  BigQuery  |  Google Cloud

///timestampとdatetime
datetime型カラムにはCURRENT_DATETIME()、timestamp型カラムにはCURRENT_TIMESTAMP()を使う
 timestampはUTC、datetimeはローカル的で地域指定ができる
 直近3分
 SELECT * FROM `aaa.ds.tbl111`
 WHERE `date` > DATETIME_SUB(CURRENT_DATETIME(), INTERVAL 3 MINUTE)

//stringとdate
func_approved_routine_a('2021-10-31') 引数がstring型
func_approved_routine_a("2021-10-31") 引数がdate型

///パーティション
パーティション分割テーブルの概要  |  BigQuery  |  Google Cloud
BigQueryのStandardSQLで日付(date, datetime, timestamp)を変換する方法 - 寝ても覚めてもこんぴうた (hatenablog.com)

パーティション分割テーブルは2種類:パーティショニングとシャーディング

1)パーティショニング
BigQueryでパーティション分割テーブルを作成する - goodbyegangsterのブログ (hatenablog.com) を見よ
パーティショニングは事前に作っておくこと
CREATE TABLE sample.n225 ( 
  trading_day DATE NOT NULL OPTIONS(description="取引日"),
  closing_quotation NUMERIC NOT NULL OPTIONS(description="終値"),
  opening_quotation NUMERIC NOT NULL OPTIONS(description="始値"),
  high NUMERIC NOT NULL OPTIONS(description="高値"),
  low NUMERIC NOT NULL OPTIONS(description="低値")
PARTITION BY
  DATE_TRUNC(trading_day, MONTH)
OPTIONS (
  partition_expiration_days=1825,
  require_partition_filter=true,
  friendly_name="日経225時系列データ",
  description="月別パーティションされた、201901から202107までの日経225時系列データ",
  labels=[("environ", "dev")]
)

クエリはpartitioned byのヤツで絞れば良い
select * from aaa_history wehre
#ParticionIDで絞る(つーかpartitioned byのヤツで日付をキャストしてUTCをJST日付に
date(rec_time) = date(datetime_add(datetime "2000-10-10 00:00:00" interval -9 hour))
AND
#実際の時間で絞る、パーティションが日付区切りなので時間検索だけなら全件検索になる
datetime(rec_time) between datetime_add(datetime "2000-10-10 00:00:00" interval -9 hour)
 and datetime_add(datetime "2000-10-10 00:59:59" interval -9 hour)

2)シャーディング
検討中… 上のパーティションも

シャーディングは_TABLE_SUFFIXを使ったり、テーブル名にハードコーディングする。
日付のキャスト select * from `task_*` where _TABLE_SUFFIX = REPLACE(CAST(date AS STRING), '-', '')

///UNNEST
UNNESTを知らないとBigQueryを使えない? | 4番は司令塔 (pep4.net)
ARRAY を一組の行にフラット化するには、UNNEST 演算子を使用
SELECT id, title FROM games, UNNEST(titles) AS title
idtitles
1[skyrim, fortnite]
2[atvvsmx, mario]
↓フラット化
idtitle
1skyrim
1fortnite
2atvvsmx
2mario

sql - How to query multiple nested fields in Bigquery? - Stack Overflow
Unnestでもflattenができず空欄ができる場合、結局left join
 空を含むカラムはSelectに残し、repeatedのカラムはleft joinでくっつける
 VariantsをunnestしてるがPricesもrepeatedなのでleft joinのものを出している
  repeatedもarrayと同じらしいが、、、cross joinやarray_to_stringもやったが駄目だった
   なおrepeated以外はunnestが効かない
それでも駄目ならselect句の指定方法やwhere句で絞ると空欄が抜けたよ
select Productid,Variants.SKU,Variants.Size
,Prices.Currency,Prices.Country
from `ga-export-0000.feed.feed_dev`
,UNNEST (Variants) AS Variants
LEFT JOIN UNNEST(Variants.Prices) as Prices 

///ARRAY型とSTRUCT型
Arrayは上のUnnestを参照。
Structは構造体型。順序付きで親子の構造を持つ。各フィールドはデータ型(必須)とフィールド名(オプション)を持つ。

array型 unnestできる、[]なのでarray_length()で数が取れる
struct型 unnestできる、ネストを含みスキーマでrecord型と表記される

struct型(record型)は子や孫でヒットすれば親を含めて表示されてしまう
見やすくするため*ではなく、カラムを特定すると空欄が表示されなくなり
親が出なくなり理解しやすくなる(必ずカラム指定したい)

例)権限が変わっていないかの確認する等
降順で最新の日付のアイテムを見る、そして最終ページの古い日付のアイテムを見る
そしてそれらを比較する
select record_time, name, asset_type, m, b.role
from cai_iam_policy_history
,unnest(iam_policy.bindings) b
,unnest(b.members) m
where record_time between timestamp('2021-05-01') and timestamp('2021-06-30')
and b.role in ("roles/bigquery.dataViewer", "roles/bigquery/jobUser")
and m like '%ketsu@bangboo.com%'
and ancestor_path like '%ketsuproject%'
order by record_time desc
SQL解説)struct型が沢山入っていても全部unnestしfromに入れればいい
 from a, unnest(iam_policy.bindings) b, unnest(b.members) m
    unnest(iam_policy)はできないので2階層目から
  一つ階層上ではunnest時に別名を付けて下の階層はその別名でunnest
struct型の子へは.ドットで指定すればいい、フラットでなくてもbでも取得ができる

通常SQLは「表.カラム」だが「親カラム.子カラム」なので、出元がどこかテーブルを探すかスキーマ内を探すかで迷う

///json_extract, json_extract_scalar
2番目の引数はパス
BigQueryでの複雑なJSON文字列の扱い方と注意点 - Qiita
標準 SQL の JSON 関数  |  BigQuery  |  Google Cloud

with t as (
    SELECT unco_data AS col_1 FROM `kuso`
    WHERE date = "2021-08-04"
)
SELECT
    json_extract(col_1, '$.color') as unco_color,
    json_extract(col_1, '$.temperature') as temperature,
    json_extract(col_1, '$.fart.times[0].stink') as first_stink,
FROM t

///Pivot
BigQueryでPreviewになったPIVOTとUNPIVOTを試す | DevelopersIO (classmethod.jp)
【SQL】クロス集計を扱う。PIVOT句とUNPIVOT句についてコードを踏まえて解説。 | ポテパンスタイル (potepan.com)
集計をして行を列に変換(生ログをある単位でまとめカラムにする)

--toolのactiveがonなら1、nullなら0でユーザAとBの状況を見る
SELECT * FROM (
 SELECT user, tool, active FROM `tools`
)
PIVOT(
 MAX( IF (active IS NOT NULL, 1, 0))
 FOR user IN ("a", "b")
)

tool a b
------------
axe 1 0
sword 0 1

※参考にピボットテーブル
集計して行を列に変換、生ログをある単位でまとめる
 生ログが「日 店 金額」の場合
 ↓
 ピボットで「日 金額 (店1 店2 店3)」にする等で、各項目を行と列と値に配置し直す

BigQueryでPreviewになったPIVOTとUNPIVOTを試す | DevelopersIO (classmethod.jp)
PIVOTの中は定数でないとだめだが、
Execute Immediate なら動的にイケる、
がGoogleSheetのConnectedSheetではサポートされておらず無理という罠

///新旧の差分
比較したいデータの共通してい部分で外部結合をしてnull部分を探す
WITH
 old_e AS (
  SELECT * FROM status WHERE user IN ('a@old.com')
 ),
 new_e AS (
  SELECT * FROM status WHERE user IN ('a@new.com')
 )
SELECT * FROM old_e o
 LEFT OUTER JOIN new_e n ON o.id = n.id AND o.date = n.date
 WHERE o.id is null OR n.id is null
 ORDER BY o.id, o.date

///REGEXP_REPLACE 正規表現で文字を削除
WITH markdown AS
  (SELECT "# Heading" as heading
  UNION ALL
  SELECT "# Another Heading" as heading)
SELECT
  REGEXP_REPLACE(heading, r"^# He", "") AS html
FROM markdown;
標準 SQL の文字列関数  |  BigQuery  |  Google Cloud

///スラッシュで分割するとarrayになるのでオフセットで取得
select SPLIT(path, "/")[OFFSET(3)] from www

スラッシュの最後を取る
ARRAY_REVERSE(SPLIT(aaa, "/"))[SAFE_OFFSET(0)]
引き当てが無い場合はSAFE_OFFSETはNullを返し、OFFSETはエラーを返す

BigQueryの標準SQLでGROUP_CONCATしたいときはSTRING_AGG - GAミント至上主義 (hatenablog.com)
逆にまとめるには
SELECT type, STRING_AGG(DISTINCT name) FROM testData GROUP BY type;
赤身 | ブリ,いわし,アジ,マグロ,カツオ,サバ
白身 | タイ,タラ,フグ,サケ

///Job kill
CALL BQ.JOBS.CANCEL('job_id')
CALL BQ.JOBS.CANCEL('project_id.job_id')

ジョブIDの取得
SELECT
 project_id,
 job_id,
 user_email,
 creation_time,
 start_time,
 --query,
 total_slot_ms
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
 --`region-us`.INFORMATION_SCHEMA.JOBS_BY_USER
 --`region-us`.INFORMATION_SCHEMA.JOBS_BY_FOLDER
 --`region-us`.INFORMATION_SCHEMA.JOBS_BY_ORGANIZATION
WHERE state != "DONE"
 --state = "RUNNING"
 --state = "PENDING"
AND user_email = 'my@email.com'
AND project_id = 'paa'
AND start_time < TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 3 MINUTE)
AND total_slot_ms > (1000 * 30)
AND PARTITIONDATE BETWEEN '2021-01-01' AND '2021-01-02'
 --PARTITIONTIME BETWEEN TIMESTAMP('2021-01-01') AND TIMESTAMP('2021-01-02')

///upsert(アップデートか新規インサート
https://swfz.hatenablog.com/entry/2021/02/08/195024
MERGE aaa target USING tmptbl src
 ON target.time = src.time
WHEN MATCHED AND src.satus = 'rejected' THEN
 DELETE
WHEN MATCHED THEN
 UPDATE SET ...
WHEN NOT MATCHED THEN
 INSERT ROW

///window関数
集約関数(GROUP BY)だと個別データは出力されず集計データだけでるが
window関数だと集計データが個別データにouter joinされた形で出力される
https://cloud.google.com/bigquery/docs/reference/standard-sql/analytic-function-concepts?hl=ja

SELECT
  deptname,
  id,
  salary,
  AVG(salary) OVER (PARTITION BY deptname)
FROM emp;

  deptname  | id | salary |  avg_salary
-----------+-------+--------+-------------
 dev        | 11 |   5200 |        5020
 dev        |  7 |   4200 |        5020
 dev        |  9 |   4500 |        5020
 dev        |  8 |   6000 |        5020
 dev        | 10 |   5200 |        5020
 hr         |  5 |   3500 |        3700
 hr         |  2 |   3900 |        3700
 sales      |  3 |   4800 |        4866
 sales      |  1 |   5000 |        4866
 sales      |  4 |   4800 |        4866

deptnameでグループしそのsalaryの集計のAVGが出ている

関数としては集計関数がそのまま使えるようだ
OVERはwindow関数を使う宣言、OVERの後にどのようにwindowを作るのかを定義
PARTITIONでwindowでつまりどの範囲でグループを作るか指定

///誰が実行しているかをセッションユーザで出す
標準 SQL のセキュリティ関数  |  BigQuery  |  Google Cloud
SELECT SESSION_USER() as user;
+----------------------+
| user                 |
+----------------------+
| jdoe@example.com     |
+----------------------+

///プログラムで使う
from google.cloud import bigquery
client = bigquery.Client()
QUERY = ('SELECT name FROM `bigquery-public-data.usa_names.usa_1910_2013`')
query_job = client.query(QUERY)
rows = query_job.result()
for row in rows:
    print(row.name)

///承認済みビュー
authorized viewを設定するとそのviewを対象とする権限だけ必要で
権限をさかのぼり付与しなくていい(通常のviewは参照元の権限も必要)
https://qiita.com/t_odash/items/65b9c965031c3120b765
 被参照の元テーブル側に許可するview名を設定する

■saturationの場合、詰まっている、サチっている
対象にクエリを発行 select 1
同プロジェクトの他のテーブルにクエリを発行 select 1
別プロジェクトから対象にクエリを発行 select 1
reservationsのoverviewを見る
対象のSQLを発行
別のプロジェクトで同SQLを発行
 時間を比べる
Google側の問題と思われるときはGoogleのサポートへGo
Google Could Status Google Cloud Status Dashboard

SELECT `b-sandbox`.test_ds.count_row(1); で実行できる
UDFやテーブル関数のルーティンを承認しておくと誰からでも使える(ビューと違い権限管理できずセキュリティがズブズブになると思われ)
 target_prj.trg_dsに受け入れる関数を共有指定する形
 UDFは戻り値がある、テーブル関数は副問い合わせとして使う形か

■課金
クエリ課金:使用しているプロジェクトで課金、データの置き場所ではない
 定額:$2000/100slot/m(全プロジェクトでスロットを共有)、オンデマンド:$5/T=2Gスキャンで1円位
 量を減らす:カラムを減らす、パーティショニング
データ保管課金:データ量
 $1/50G/m
6,000スロットを使うBigQueryのリソース配分最適化への挑戦 (plaid.co.jp)
サポートを付けるとGoogleに聞き放題になったりする

■権限
事前定義ロールと権限  |  BigQuery  |  Google Cloud
job user:select文クエリ実行だけでもジョブでjob userとdata viewerが要る(data viewerだけでは不足)
 課金プロジェクトでjob userを持ち、参照先プロジェクトでdata viewerを持つという権限構成だから
IAMかデータセット/tblに必要な権限を付与する
 data editorでも自分で作成したものは自分がOwnerになり削除や変更権限がある

■IAM(Identity and Access Management) 
https://www.bangboo.com/cms/blog/page_347.html


Posted by funa : 01:00 AM | Web | Comment (0) | Trackback (0)


February 10, 2021

Python
おッPythonやるのか?

ファイル拡張子oppython.py デフォUTF-8、全部オブジェクト(list,dict,set等のミュータブルなら参照になる点に注意、必要ならcopy())
#コメント、ドキュメントストリング(三連引用符):"""そのまま表示""" print mymod.__doc__で見れる
変数型不要:p = 500 * num、定数はない
文字繰り返し、キャスト:"文字列" * 4 + str(p) + "Hi\nお元気ですか?\nSee u"
raw文字列でescしない:print(r"インストール先は c:\\code\python\bin です")
文字数:len("東京都")→3
文字列[開始:終了]→→ str = "Flower" print(str[1:4]) → low
文字列 % (値1, 値2, ...)→→ num= "10進数では %d 、16進数では %x " % (num, num)
"xxxx{index:書式指定子}xxxx".format(値)→→ "名は{:<8s}で年は{:>3d}で".format(name, age)
f"xxxx{値:書式指定子}xxxx"→→ f"名は{name:<8s}で年は{age:>3d}で" 
0/空の文字列''/値なしはfalse、Noneは? x = None x is None→→true?
//→除算切り捨てし整数、**→べき乗
関数宣言はdef kansu():だが、その中からglobal henでグローバル変数henにアクセスできる
返り値複数はcsvでタプルになる、リストが楽か? return a,b → (a, b) あるいは return [a, b] → [a, b]
try/exceptを関数内で設定することも、逆に関数呼び出し時にも使用ができる、else, finally, raiseも使う
とほほのPython入門 - リスト・タプル・辞書 - とほほのWWW入門 (tohoho-web.com)
リストa=[1,2,3]はmap(), filter(), reduce()等が使える、set()は重複の無いリストを扱いセット同士の減算、OR、AND、XOR 操作が可能
tuple→タプルは定数リスト、更新無しならリストより速い a = 1,2,3 a = (1, 2, 3)
dict→辞書は連想配列みたいな{a:1,b:2}はitems(), keys(), valus(), iteritems(), get()を使える
lambdaは無名関数?
str_w = input('何か入力してください-->') #入力させた値を取れるが数字もstr
__iter__()はnext()を持つオブジェクトを返し、next()は次の要素を返し、最後に達するとStopIteration例外を返す?
yield はイテレータを返すジェネレータを定義?
@デコレータは関数を実行する前後に特殊な処理を実行したい場合?
withで終了処理を指定できる、ファイル読込とその後の処理とか
assertや__debug__はテストで機体通りかを確認する?
passは中身の無い関数やクラスを作成しkara.p=1で粋なり属性追加等ができる
execは引数の文字列をPythonとして実行 exec "print 'Hello'"
delはオブジェクトを削除 del x, y, z
継承やオーバーライド class MyClass2(MyClass):
多重継承class MyClassC(MyClassA, MyClassB): で纏めて使えるようになる
class MyClass:
    """A simple example class"""  # 三重クォートによるコメント
    def __init__(self):  # コンストラクタ
        self.name = ""
    def __del__(self): #インスタンスが消滅する際に呼出でコンストラクタ
        print "DEL!"
    def __str__(self): #文字列化
        return "My name is " + self.name
    def getName(self):  # getName()メソッド
        return self.name
    def setName(self, name):  # setName()メソッド
        self.name = name
class MyClass2(MyClass):
    def world(self):
        print "World"
class MyClass3(MyClass):
    def hello(self):  # 親クラスのhello()メソッドをオーバーライド
        print "HELLO"
a = MyClass()  # クラスのインスタンスを生成
a.setName("Tanaka")  # setName()メソッドをコール
print a.getName()    # getName()メソッドをコール
print a  #=> My name is Tanaka 文字列化
b = MyClass2()  #継承
b.hello()    #=> Hello
b.world()    #=> World
c = MyClass3()  #オーバーライド
c.hello()    #=> HELLO
super()を使ってオーバーライドする
 super()は基底クラスのメソッドを継承した上で処理を拡張
 super().__init__(x、y)が使える
with構文で処理の前後で__enter__、__exit__を使う
 __enter__メソッドで事前処理
 __exit__メソッドで事後処理
if __name__ == "__main__":
 モジュール時の勝手実行を抑える
  import helloの時hello.py 内部での __name__ は "hello" 
  python hello.pyのような実行時hello.py の内部の __name__ は "__main__"
from math import pi, radians→mathモジュールから特定のオブジェクト(関数/変数/クラス)をimpo
import urllib.error→urllibパッケージからerrorモジュールをimpo、パッケージはフォルダ
import numpy as np→別名でしか使えなくなるnp.array()とかで
 モジュール=ファイル名.pyでファイルをimpoしている
 impo順:標準ライブラリ>サードパーティライブラリ>ローカルライブラリ(自作のライブラリ)

関数や変数:小文字スネークケース(sample_func)
クラス名、例外、型変数:キャピタルパスカルケース(SampleClass)
定数名:大文字アンダースコア区切り(SAMPLE_CONST)
モジュール名:小文字(samplemodule, sample_module)
パッケージ(フォルダ)名:小文字。アンダースコア非推奨(samplepackage)

インデントは半角スペース4つ
1行半角で79文字以内
トップレベルの関数やクラスは2行開ける
クラス内部では1行ずつ開けてメソッド定義
ドックストリングでクラスや関数についてコメントする(慣習的にダブルクォート)
 コード中は処理についてのコメントをなくし関数化とdocstringで参照するように
 「コメント(#)とdocstring(""")の違いは?」コメントとdocstringについて
 [Python]可読性を上げるための、docstringの書き方を学ぶ(NumPyスタイル) - Qiita

※参照になりコピーされない、必要ならコピー(値を入れた時点で参照が外れるので実際問題少ない?)
a = []
b = a
b.append(1)
print(a) #[1]
https://qiita.com/ponnhide/items/cda0f3f7ac88262eb31e
https://nishiohirokazu.hatenadiary.org/entry/20120125/1327461670

※テキスト選択
 Shift↑or↓ で行全体
 home(+fn)で行頭、end(+fn)で行末移動

【基礎一覧】Pythonの基本文法を全て解説してみた!【初心者】 (suwaru.tokyo)
Python基本文法まとめ - Qiita
とほほのPython入門 - とほほのWWW入門 (tohoho-web.com)
Python入門 ~Pythonのインストール方法やPythonを使ったプログラミングの方法について解説します~ | Let'sプログラミング (javadrive.jp)
Welcome to Python.org

HTMLの中に少し埋め込めず、基本的にプログラムの中にHTMLを埋め込む:CGI(Perl然)
 さくらインターネットでPython CGI (mwsoft.jp)
WSGI Python で WSGI (Web Server Gateway Interface) に従ったシンプルな Web サーバで Hello World - Qiita
Python用Webサイト用途フレームワーク:Flask(軽量)、Django
 WSGI について — Webアプリケーションフレームワークの作り方 in Python (c-bata.link)
 GCPでどう使うかは不明だがホスティングは↓
 ウェブ ホスティング | Google Cloud 静的ウェブサイトのホスティング  |  Cloud Storage  |  Google Cloud

==============
ここで動かせるgoogle colaboratory→ Colaboratory へようこそ - Colaboratory (google.com)

コラボラトリはマークダウン Qiita マークダウン記法 一覧表・チートシート - Qiita
半角スペース2個で改行
#の数で見出し
*で箇条書き
数字と.で番号を振る、- でリスト
* or - or _ を3つ以上で水平線
[ ]でチェックボックス、[x]でチェック
| td | td | td |でテーブル
**aaa**で太字、*aaa*で斜体
~~aaa~~で打消し線
[タイトル](URL)でリンク
```でコードの挿入、`でインライン挿入
> or >> で引用
 [^1]で注釈
\バックスラッシュでマークダウンのエスケープ

==============
宗教論争(事実は同じでも他人の認知は違うので意味なし
if self.flag_ok == 1 and self.mode == '1'
↓一見で分からんなら変数名を工夫してこうやんな
if self.file_verify_completed and self.mode == GRANT_PERMISSION:

マジックナンバーを使わない(数字の方が曖昧性が無い場合も)
STATUS_ERROR = -1
STATUS_SUCCESS = 0
self.status_error = STATUS_SUCCESS

初期値をエラー値にし、業務判定エラーでステータスを設定したらreturnで抜ける
def exFunction(self):
self.status_error = STATUS_ERROR
try:
if XX = AAA:
self.status_error = STATUS_XX_ERROR
retrun
self.status_error = STATUS_SUCCESS
retrun
except:
~エラー処理、ステータスは変更しない

エラーメッセのハードコーディングを避ける方法(ハードが場所と内容が分かり易いかも)
MSG_ERROR_OLD_EMAIL = "Error: 旧メール%sです\n"
e_message_list.append(MSG_ERROR_OLD_EMAIL % (old_email))
self.error_message = '\n'.join(e_message_list)


ケチって分厚い本1冊にしたが全然進まぬ、薄い奴星e、?チッPython、誰がJSONじゃ~い、チェーンソー魔わすっぞ



Posted by funa : 07:30 PM | Web | Comment (0) | Trackback (0)


December 25, 2020

Promise
仕事は炎上芸なり~と勤しむ炎上芸人にも分かるように解説をさせて頂きたく候
(勤しむところはソコではない)

///promise/async/await 非同期関数
https://rightcode.co.jp/blog/information-technology/javascript-promise
https://rightcode.co.jp/blog/information-technology/javascript-async-await
http://www.tohoho-web.com/ex/promise.html
https://sbfl.net/blog/2016/07/13/simplifying-async-code-with-promise-and-async-await/
https://qiita.com/niusounds/items/37c1f9b021b62194e077
https://qiita.com/soarflat/items/1a9613e023200bbebcb3
非同期関数は処理の順序を制御できない問題があった、そこでPromise
Promise オブジェクトは then(ok_callback, ng_callback) というメソッドを持ちます。
then() はPromise が成功または失敗になるまで処理を受け流し、
処理を.then()で繋げ順番を確保することが可能
成功時に ok_callback を、失敗時に ng_callback をコールバック関数として呼び出します
.then() は第一引数に成功時のコールバック関数、第二引数に失敗時のコールバック関数
.catch(ng_callback) は、.then(undefined, ng_callback) と同じ意味
.catch() は処理中に発生した throw をキャッチできる
ES2018(ES9) では、.finally() がサポートされました
function aFunc3(data) {
    return new Promise(function(okCallback, ngCallback) {
        setTimeout(function() {
            if (Math.random() < 0.30) {
                ngCallback(new Error('ERROR!'));
            } else {
                okCallback(data * 2);
            }
        }, Math.random() * 1000);
    });
}
function sample_finally2() {
    aFunc3(100).then((data) => {
        console.log(data);
        return aFunc3(data);
    })
    .then((data) => {
        console.log(data);
        return aFunc3(data);
    })
    .then((data) => {
        console.log(data);
         throw new Error('ERROR!!!');
    })
    .catch((e) => {
        console.log("catch");
        console.log(e);
    })
    .finally(() => {
        console.log('*** Finally ***');
    });
}
//200 400 800 catch Error:ERRROR!!! *** Finally ***
Promise.all() は配列で指定された全てのPromiseタスクを待ち全てが完了した時点で .then()を呼ぶ
Promise.race()ならいずれかのPromise
function sample_all() {
    p1 = taskA();
    p2 = taskB();
    Promise.all([p1, p2]).then(() => {
        console.log("taskA and taskB are finished.");
    });
}
ES2017 では、async/await がサポートされました
async と await を用いることで、Promise に対応した非同期関数を、同期関数の様にシンプルに呼び出すことが可能となります
同期関数の様に呼び出したい非同期関数を呼び出す際に await をつけます。await を呼び出す関数に async をつけます
async function sample_async_await_with_catch() {
    var val = 100;
    try {
        val = await aFunc3(val);
        console.log(val);
        val = await aFunc3(val);
        console.log(val);
        val = await aFunc3(val);
        console.log(val);
    } catch (e) {
        console.log(e);
    }
}

■コールバック関数
広い定義でいうと「高階関数に渡すための関数」
「関数を受け取る関数」は「高階関数」、つまりhello()がコールバック関数
// 関数を2回実行する関数!!
function doTwice(func) {
  func(); // 1回目Hello!
  func(); // 2回目Hello!
}
// あいさつするだけの関数
function hello() {
  console.log('Hello!');
}
// あいさつを2回実行する
doTwice(hello);

========================================
もっと詳しく、もっと分かり易く、どう使うか↓

https://knowledge.sakura.ad.jp/24890/
https://jsprimer.net/basic/async/
https://dev.classmethod.jp/articles/javascript-asynchronous-processing/
■処理の繋がり
1)コールバック関数
 ある関数の処理が終われば次のコールバック関数を呼ぶという指定がそれ
 歴史的にはエラーファーストコールバック(のルール)
  処理が失敗した場合は、コールバック関数の1番目の引数にエラーオブジェクトを渡して呼び出す
  処理が成功した場合は、コールバック関数の1番目の引数にはnullを渡し、2番目以降の引数に成功時の結果を渡して呼び出す
  fs.readFile("./example.txt", (error, data) => {

2)Promise(非同期処理に対するPromise→順番を合わせる意味では同期処理ではと思う?JSはシングルスレッドかつ非同期という糞?仕様)
 ある関数の処理が終わればPromiseオブジェクトを返す
 JSがシングルスレッドだが 処理を一定の単位ごとに分け処理を切り替えながら実行する並行処理(concurrent)の仕様のため 順序を考慮する必要がある
  非同期処理の実行中にとても重たい処理があると非同期処理の切り替えが遅れる

Promiseオブジェクトは3つの内部状態を持ちます。
 pending(保留): まだ非同期処理は終わっていない(成功も失敗もしていない)
 fulfilled(成功): 非同期処理が正常に終了した
 rejected(拒否): 非同期処理が失敗した
  初期状態はpendingで、一度fulfilledまたはrejectedになったらそれ以降は状態は変わらず、非同期処理の終了時に返す値もそれ以降は変わらない

Promiseのコンストラクターは関数を引数に取って、その関数がさらに2つの関数を引数に取る
 1番目の関数(resolve)に引数を渡して実行すると状態がfulfilledになり、引数の値はPromiseオブジェクトが保持する値になる
 2番目の関数(reject)に引数を渡して実行すると状態がrejectedになり、引数の値はPromiseオブジェクトが保持する値になる
 関数が例外を投げた場合も状態がrejectedになり、投げた値がPromiseオブジェクトが保持する値になる、throwする値をrejectedに渡して実行した時と同じ

then()は2つの関数を引数に取り、Promiseの状態がfulfilledになったら1番目の関数が、rejectedになったら2番目の関数が実行されます。
 then()の1番目の引数が関数でなければidentity function(入力値をそのまま返す関数)が代わりに使われます
 2番目の引数が関数でなければthrower function(入力値を例外として投げる関数)が代わりに使われます
  catch()は1番目の引数にidentity functionを指定したthen()と同じ

上の挙動をオレオレPromiseをYakusokuで作っているので分かり易い https://knowledge.sakura.ad.jp/24890/

なお、本質としてはコレ、下記ソースが決まりの流れ、ひな形としてヤリ慣れるしか
1)時間が掛かる処理をPromise化して順序立てよう
2)成功と失敗のコールバックを指定しよう

//処理にコールバック関数を入れて成功と失敗時の型で終える
function dummyFetch(cmt, callBack) {
    setTimeout(() => {
        if (cmt.startsWith("/success")) {
            callBack(null, { body: `Response body of ${cmt}` });
        } else {
            callBack(new Error("Bad"));
        }
    }, 1000 * Math.random());
}
//プロミスを入れるためラッパーを関数にかます
function aaaFilePromise(cmt) {
  return new Promise((resolve, reject) => {
    dummyFetch(cmt, (err, data) => {
      if (err) {
        reject(err); // 失敗: 内部状態をrejectedにする
      }
      else {
        resolve(data); // 成功: 内部状態をfulfilledにする
      }
    });
  });
}
//プロミスチェーンでのフロー
aaaFilePromise("/success/passwd")
  .then((data) => { // 読み出しに成功したらresolve()に渡した値が引数として渡される
    console.log("1", data);
    //return 'next';//テキストがあってもなくても次のthenに行く、省略でもテキストでも第一引数関数に行く成功側
    return aaaFilePromise("/etc/text");//エラーで次のthenの失敗側の第二引数関数にきっちり行く
  })
  .then((data) => {
    console.log("2", data);
    return aaaFilePromise("/success/shadow1");
  }, (data) => {
    console.log("2e", data);
    return aaaFilePromise("/success/shadow2");
  })
  .then((data) => {
    console.log("3", data);
    return aaaFilePromise("/etc/shadow");
  })
  .catch((err) => { // reject()に渡した値が引数として渡される
    console.log("error", err);
  });

then()/ catch()は、引数で渡された関数の戻り値から新たにPromiseオブェクトを作り、そのオブジェクトを返します。そのためメソッドチェーンが可能
  引数に渡した関数の戻り値がPromiseオブジェクトの場合はそのオブジェクトをそのまま返す、そうでなければ戻り値をPromiseで包んで返す
 エラーでキャッチに飛ぶ訳ではなく次のthen第2引数関数に飛んでいる、省略でcatchに行っているように見えるだけ

dexieやPWAでの提供があり使う(処理を順序立てて使うようプログラムを組む時に
dexie: db.schedule.where('site').equals('sche').first().then(function(records) {
pwa: caches.keys().then(function(keyList){
return Promise.all(keyList.map(function(key){

3)async / await
promiseは順番決めができたがasync/awaitは順番を扱う処理もできる
setTimeout/setIntevalがプロミスチェーンだけでは時間を止められない
 シングルスレッドから似非スレッドで分離し非同期になるから、awaitを入れると同期する↓
const wait = (sec) => {
  return new Promise((resolve, reject) => { setTimeout(resolve, sec*1000);  });
};
async function arrKick_async(arr) {
    for(let i=1; i<=num_arr; i++){
      arr = await kickPromise(arr);
      await wait(2);
    }
}
arrKick_async(arr);

========================================
JSネイティブとPromiseとasyncが混ざった場合は同期しない、then()すら超えてくる↓

4)コールバック地獄
結局コールバック地獄が扱いやすい(スレッドの切り替えがなければ同期ができる)、最近のJSフレームワークは全部Promise化しているらしいが

例)キャッシュを保存し、そのステータスを取るようにAsyncやPromiseで保存待ちの順番をにしても、待たない

//隙間がないと1度エラーだとエラーになりっぱなし
let num_cache;
num_cache = getCacheStatus();
if(num_cache == 0 || !num_cache){
num_cache = getCacheStatus();
if(num_cache == 0 || !num_cache){
num_cache = getCacheStatus();
if(num_cache == 0 || !num_cache){
num_cache = getCacheStatus();
if(num_cache == 0 || !num_cache){

//setTimeoutで隙間があっても関数スレッドの返り値を代入するスレッド切替時に、返り値を待つスレッドの方は次の処理に進んでしまいIF判定ができない
let s = setTimeout(function(){
let num_cache1 = getCacheStatus();
if(num_cache1 == 0 || !num_cache1){
s = setTimeout(function(){
let num_cache2 = getCacheStatus();
if(num_cache2 == 0 || !num_cache2){
s = setTimeout(function(){
let num_cache3 = getCacheStatus();
if(num_cache3 == 0 || !num_cache3){
s = setTimeout(function(){
let num_cache4 = getCacheStatus();
if(num_cache4 == 0 || !num_cache4){

//Func返り値やPromiseやAsyncでのスレッドの切り替えがないDOMの判定であれば上手くいく
let s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == 'none'){
s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == 'none'){
s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == 'none'){
s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == 'none'){
s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == '<?php echo $lang_page->install_none; ?>'){

function getCacheStatus(){
let num_caches = 0;
let num_success = 0;
caches.keys().then(function(keyList){
  return Promise.all(keyList.map(function(key){
caches.open(key).then(function(cache) {
cache.matchAll().then(function(response) {
document.getElementById('mes_filenames').innerHTML = '';
let s;
let o;
for(const value of response){
s = value.status;
o = value.ok;
document.getElementById('mes_filenames').insertAdjacentHTML('afterbegin', value.url + '<br>');
if(s == '200' && o){
num_success++;
}
num_caches++;
}
if(num_caches > 0){
document.getElementById('mes_progress_rate').innerHTML = 'Progress: ' + num_success / num_caches * 100 + '%';
}else{
document.getElementById('mes_filenames').innerHTML = 'None';
}
});
});
  }));
});
return num_caches;
}
===============
thenの入れ子だと親の部分だけ先に進んでしまう、入れ子ダメで親子を作れば親→子の一方方向で子で終わるトーナメント構造で(上がらない)
test1().then((result) => {
test2().then((result) => { //fuok });
})then(function() これは入れ子

test1().then((result) => {
test2().then((result) => {
//fuok
})then(function(){ //fuok2 }); これでトーナメント構造
})catch(function(e)

promiseチェーンでthen毎にに欲しい引数を出すが、複数であればそれらの引数をthenに渡せない、下記1は駄目
 1)thenで一つの引数になるようにロジックを組む(thenのトーナメント構造、一階層上で変数に入れる等)
}).then(function(response){
return [response.json(), arr_del];
}).then(function(v) {
json = v[0]; arr = v[1];
 2)callbackとresolveに配列を使うとOK、オブジェクトでもいいかも
function dummyFetch(cmt, callBack) {
if(Array.isArray(cmt){
var p = cmt[0];
var s = cmt[1];
}else{
var p = cmt;
var s = 1;
}
setTimeout(() => {
        if (p.startsWith("/success")) {
var r = [p, ++s];//これ不可[p, s++]
callBack(null, r);
        } else {
            callBack(new Error("Bad"));
        }
    }, 1000 * Math.random());
}
function aaaFilePromise(cmt) {
  return new Promise((resolve, reject) => {
    dummyFetch(cmt, (err, data) => {
      if (err) {
        reject(err);
      }
      else {
        if(Array.isArray(data){
var p = data[0];
var s = data[1];
}else{
var p = data;
var s = 1;
}
resolve([p, s]); // 成功: 内部状態をfulfilledにする
      }
    });
  });
}
===============
Promise化していない関数を使いたいが、そのまま使うかthen化できるようにするか?
 1)次thenに進みたい元Funcの処理としてresolveの返り値に入れる、ダメなら省略可だがreject()に渡しcatchする
 2)次thenには適当でもいいのでreturnで進む
function test1 () {
  return new Promise((resolve, reject) => {
    const a = 1;
    const b = 2;
    resolve([a, b]);
  })
}
test1().then((result) => {
  console.log(result[0]); // 1
  console.log(result[1]); // 2
  return 'go next';
}).then(function(){

エラーハンドリングしたい、よくわからんが下記で動作に違いがでた、rejectはJSがエラーを吐いた
 1)catchさせるにはthrow new Errorし、alertを出す
 2)catchはしないが次のthenには移動させないためreturn false
}).then(function(json){
if(json.init == 'Not appropriate access'){
throw new Error('Server warning');
}else if(json.init == 'No data'){
//reject("initiate!");
return false;
}else{
resolve(json);
}
}).catch(function(error){
alert('Ooops:  ' + error);
});
Promise.allを使って、3つのpromiseを同時に実行、allはすべての非同期処理がresolveされたタイミングで結果を返
Promise.all([test1, test2, test3]).then(function() {
    console.log("Fourth");
もっと簡単に async, await, Promise - Qiita

■Javascript
https://www.bangboo.com/cms/blog/page_325.html

Posted by funa : 01:06 AM | Web | Comment (0) | Trackback (0)


April 21, 2020

Dexie
Indexeddbを使うならラッパーが要るやろ、とオモて、溺死やったらコレ便利やんってちゃうか、とオモて、知らんけど

■構造 DB > Table > kvs > record
(db=)schedule_db > schedule(=table) > kvs(Key=自動採番:Value=json=record)

kvsはid++が先頭に来ずでこう→ 1:"{"name":"aaa",reg_date":"20201027_11:57:24","id":1}"

var db = new Dexie("schedule_db");
db.version(1).stores({
schedule: '++id,name,reg_date'
});

■操作
var db = new Dexie("schedule_db"); schedule_dbというDBがセットされ
schedule: '++id,name,key,reg_date' テーブルscheduleにカウントアップKey:JSON{id,name,key,reg_date}が入る
もしschedule: 'name,key,reg_date'ならnameが自動で一番最初のカラムだからキーになる
キーの値が同じだとAddができない

stores()で一番最初に来るのが「主キー」
put()は追加しあれば更新、add()は追加のみで同キーがあればエラー
 put()はupdateとしてDB上上書きされるように見えるがループすると全データが出てくる、謎
first()やlimit()やlast()で欲しいレコードを取得
toArray()ではobjが返るがobjは配列で引数0をつけてアクセス obj[0]
get('aaa')はkey=aaaの値を持つ最初の行、get({key: "sss", value: "ccc"})で条件付可
delete()の返り値Promiseに削除件数が入っている

■削除のレベルは行、表、DB
行削除 db.schedule.where({id: id}).delete().then (function(records){
表削除 trancateで db.schedule.clear(); コンソールには反映されていないがレコード削除済
 db.table(storeName) で操作あるいはtables ->だめだった
 表を複数持てる
db.version(1).stores({
    genres: '++id,name',
    albums: '++id,name,year,*tracks',
    bands: '++id,name,*albumIds,genreId'
});
db.delete() DBを消せる(その後新たに再作成できる)

■insert
db.schedule.add({name: "aaa", key: "bbb", reg_date: getCurrentTime()}).then (function(id){
return db.schedule.get(id);
}).then(function (schedule) {
alert ("Date was set at " + schedule.reg_date);

■select
db.reserve.each(function(records){
if(records == null || records == ''){
alert ("No data found");
}else{
records.json;

toArrayは複雑になる、eachの方がよいかも、toArrayとeachの入れ替えてのselect発行が基本できるみたい
db.reserve.where({flg_del: 2}).toArray(function(records){
records.forEach(function(record){//obj.forEach直で行ける
Object.keys(record).forEach(function(key) {//直で行けずObject.keys().forEach()で
let val = this[key];
if(key == 'json'){
let v = JSON.parse(val);//直で行けずパースが必要
Object.keys(v).forEach(function(k) {
let v = this[k];
console.log(k, v);
}, v);
}
}, record);
});

複雑なものはOr句で出せる
db.reserve.where('reg_date').below(getCurrentTime()).or('flg_del').equals(2).limit(3).each(function(records){
console.log('List: ' + JSON.stringify(records));

And句はfunctionを取るが簡単な感じがする
db.reserve.where('datetime').below(display_expire_date).and(item => item.flg_del == 2).desc('datetime').limit(display_ex).each(function(records){

複数条件はwhereにオブジェクトとして記載するがbelow等のフィルターにつながらずエラー、シンプルならokだが
db.reserve.where({datetime, flg_del: 2}).below(display_expire_date).limit(display_ex).each(function(records){
複数条件にフィルターをつけるにはwhereに配列で記載するが一つはbelow、一つはequalsでフィルタが複数でうまくいかない、シンプルならokだが
db.reserve.where(["datetime", "flg_del"]).below([display_expire_date, 2]).limit(display_ex).each(function(records){

先頭行
db.schedule.where('name').equals('aaa').first().then (function(records){

x↓ダメ??
db.schedule.where('name').equals('aaa').toArray(function(records){
alert(records.reg_date);

x↓ダメ??
db.schedule.get({name: "aaa", key: "bbb"}).then (function(records){
alert (JSON.stringify(records));
for (let i in records) {
alert(i + ' item has ' + records[i].reg_date);
}

■Insert and select(キーのidを使う)
db.schedule.add({name: "ver1.0", key: document.getElementById("inputKey").value, value: document.getElementById("inputValue").value, reg_date: getCurrentTime()}).then(function(){
db.schedule.get('2').then(function(records){
alert(JSON.stringify(records));
}).catch(function(error) {
alert ("Ooops: " + error);
});
}).catch(function(error) {
alert ("Ooops2: " + error);

■Update
putは存在があれば更新、なければ挿入
db.schedule.put({key: "bbb", reg_date: set_date}).then (function(){
return db.schedule.get('bbb');
}).then(function (schedule) {
alert ("Date was set at " + schedule.reg_date);

keyが出せる場合はupdate()
db.friends.update(2, {name: "Number 2"}).then(function (updated) {

トランザクションや細かな変更はmodify()
db.friends.where("shoeSize").aboveOrEqual(47).modify({isBigfoot: 1});
 modify推奨?→ https://dexie.org/docs/Collection/Collection.modify()

■Delete
db.schedule.where({name: "aaa"}).delete().then (function(){
return db.schedule.toArray();
}).then(function (records) {
if(records == null || records == ''){
alert ("No data found");
}else{
alert (JSON.stringify(records));
}

■Where句
db.friends.where("shoeSize").between(40, 45).count(function(count) {
[HTML5] IndexedDBでデータの保存や読み込みを行う - Dexie.js編 (katsubemakito.net)
Dexie.jsとTypeScriptでIndexedDBを操作する - noxi雑記 (hateblo.jp)

■アクセス
indexeddbは該当DBにどこからアクセスできるか>同一ドメイン、ディレクトリでじゃない
保存場所
C:\Users\<ユーザ>\AppData\Local\Google\Chrome\User Data\Default\IndexedDB
C:\Users\<ユーザ>\AppData\Roaming\Mozilla\Firefox\Profiles\XXXXX.default\storage\default

■課題
SWで外部JSを扱うにはSW内に importScripts('dexie.js'); で埋め込む
SyntaxError: Unexpected token o in JSON at position 1 はオブジェクトが返っている
JSONはオブジェクトで扱うのが楽 JSON.stringify(records)とJSON.parse(records)で変換
console.log('json: ' + JSON.stringify(json));
for(i = 0; i < json.length; i++){
if(json[i] != null) {
console.log('id: ' + json[i].id);
下のようなロジックはあるテーブルのSELECTループ中に他のテーブルにアクセスする入れ子なのでエラー「NotFoundError: Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found.」→配列に入れてIndeDBの問い合わせを一旦完了し、配列のループでIndedbを操作
self.addEventListener('sync', function(event){
db.que.each(function(records){
if(event.tag.startsWith('post-data:' + records.tag)){
event.waitUntil(postDataSW(db));
}
});
function postDataSW(){
db.reserve.where({flg_server: 2}).toArray(function(records){
DevTools failed to load SourceMap: Could not load content~のエラーが出た
 効果あるか不明だがdexieの最終行のコレを削除した、文字コードがUTF8に変えたりも //# sourceMappingURL=include.prepload.js.map

■関連JS、Javascript
JSでAタグリンクを挿入するにはinsertAdjacentHTMLがよい
生成したタグを追加する前に掃除するにはdocument.getElementById('xx').textContent = null;

■テスト
https://www.bangboo.com/indexeddb/indexeddb_dexie_form.html
https://www.bangboo.com/indexeddb/test/indexeddb_dexie_form.html (ディレクトリ違い)

Posted by funa : 12:00 AM | Web | Comment (0) | Trackback (0)


April 20, 2020

PWA

■PWA
https://digital-marketing.jp/seo/what-is-progressive-web-apps/
https://developers.google.com/web/fundamentals/architecture/app-shell?hl=ja
https://qiita.com/kimamula/items/4e25b8d2caca314f9dd2
https://html5experts.jp/osamum_ms/25709/
Service Worker, App Shell Model, PRPL Petternなどを駆使したGoogleが提唱するProgressive Web Apps
HTML / JS / CSS だけでほぼ構成、モバイルApp的なWebが提供できる
SW(JS)がブラウザとサーバの間に位置し、データを取ったり渡したりブラウザの影/裏側で動く、サーバと考えてしまうと分かり易い?
App Shell Modelで側(画面テンプレート)をプッシュしておくと早い(JSレスポンス悪すぎるからコレってな)

PRPLは以下の略
 Push: 最初のURLルートに不可欠なリソースを Pushする。
 Render: 最初のルートを Renderする。
 Pre-cache: 残りのルートをPre-cache(事前キャッシュ)する。
 Lazy-load: オンデマンドで残りのルートをLazy-load(遅延読み込み)する。

/// Service Worker
訪問がない状態でのバックグラウンド同期、プッシュメッセージ
データの更新を集中的に受信して複数ページがデータの一部を利用(ブラウザにインストールするプロキシ、コンテンツの管理やキャッシュ管理を行える)
https://developer.mozilla.org/ja/docs/Web/API/Service_Worker_API
https://qiita.com/kei4eva4/items/fa5f99211e45b7ca6f6e
 →正確にはバックグラウンド同期では無い>periodic background syncはユーザに粘着可で無くなりそう
 Periodic Background Sync 及び Web を Install するということ | blog.jxck.io
 スコープへアクセスがあった場合にキャッシュの更新はできる、あるいは
 syncをオフ時に仕込んでおけばオンライン時にバックグラウンド同期は可能
 beacon apiを実行させると離脱時にサーバに通信も可能


Webページとは別にバックグランドで実行するスクリプト(マルチスレッドになると思う)
ブラウザでキャッシュ操作ができる、容量もあり強力、データ期限や破棄に注意
 DOMに直接アクセスできない
 ブラウザを開いていなくても動作可能
 プログラム可能なネットワークプロキシとして動作可能
 HTTPS必須(またはlocalhost)
ネットワークに依存しない、早い(阿部寛はもっと早い)、プッシュ通信、ホームに追加
 
/// プッシュ配信
https://liskul.com/push-notification-25520
https://www.fenrir-inc.com/jp/boltzengine/
https://pushnate.com/labs/pushnate/webpush-case-guide

事前のコンセントがなくいきなり「プッシュ通知を有効にしますか」と出てくるのは駄目
ユーザーに何の通知をするかを知らせたい
通知から訪れたときの表示と挙動を決めておく
セグメントを分けて送りたい場合はセグメントの情報をどうやってブラウザからたどってくるか
スマホではアプリのインストールが必要だが、Webプッシュはブラウザさえあれば通知ができる
https://webtan.impress.co.jp/e/2018/12/06/31214
通知の許可のダイアログを出す前にダイアログで説明
https://push.appirits.com/webpush/

過去評価の高かったボケが、1日1つプッシュ通知で配信
1日1回、時間帯としては「20時前後」に4回に分けて(通常19:50、20:00、20:10、20:20)配信
年末年始やGWだけは、昼と夜に(1日2回)
DAUに15〜20%くらい影響がでます。「プッシュしないとアプリを開かない人」が一定数いる
アクティブ度、アプリのバージョン、端末のOS、属性(男女)などで、セグメント配信
休眠ユーザーだけにプッシュ1万人に1人くらい(0.01%)しか起動せず難しい
https://appmarketinglabo.net/bokete-push/

配信方法は現在ではChromはGCMを、FirefoxはSimplePushサーバを利用
 受信する端末ごとに異なるメッセージを送るにはGoogle Firebaseが使われる様である
 https://android.googleapis.com/gcm/send https://updates.push.services.mozilla.com/push/
その許可を得たプッシュのエンドポイントを使用し配信
GCMの場合1度の送信で1000デバイスまで同時に指定できる、FirefoxのSimplePushでは1デバイスでの送信
デスクトップ/Webの場合はデスクトップに通知される(Win10の場合?Win7でも通知が来る)
https://qiita.com/zaru/items/f6e821052abb1b18bb0b
https://techblog.asahi-net.co.jp/entry/2018/09/28/173705
 ここにブラウザのベンダーの提供サービスを通じてとある(モバイルはコレしか)
 サーバーからブラウザを通じてデスクトップ通知する方法(Push API を利用) – ラボラジアン (laboradian.com)

/// 結局
キャッシュを弄くってオフラインでもゴニョゴニョできる、先読みも可、プッシュ通知も可、モバイルAppぽく
 →G suiteのOfficeアプリがオフラインでもサクサク、メール受信通知もできるGoogleのG suite用みたいなもんか
 →PCよりスマホを売りたい、通信量でも儲けたいfbgcp、個人情報を取りたいので、モバイル優先、モバイルっぽくWeb、これはi-modeやね

UR evil.

■どのようにPWA化するのか
https://techblog.asahi-net.co.jp/entry/2018/07/06/145931
https://techblog.asahi-net.co.jp/entry/2018/08/10/175407
 1)Service Worker(PWAで必要な処理を記述するJavaScriptファイル)
 2)Manifest(PWAの仕様について記述するJSONファイル)
 3)アイコン…ショートカットアイコン、プッシュ通知時のアイコンや起動画面で配置する画像

navigator.serviceWorker.register('/servicew.js').then JSファイルを登録(中に下記を入れ込む)
 //キャッシュ動作部分
 ├addEventListener('install' キャッシュのインストール
 ├addEventListener('activate' アクティベート
 └addEventListener('fetch' オフラインでもアクセスの際にクライアントが呼んでキャッシュ取得
 //通知部分
 ├addEventListener('push で通知を受ける
 └addEventListener("notificationclick で通知クリック時の挙動
Notification.requestPermission(function(status) { 通知許可は登録JS外でOK

キャッシュはリンク先も保持する?、、、→せえへんけど?
ブラウザのURLの鍵アイコンをクリックすると通知許可を含めて設定ができる(デフォルトの確認、許可、ブロック)
 デフォルトとブロックの時は「Push通知On」のボタンを表示 → ボタンを押すとダイアログで何が通知されるか表示しOKボタンを押せる
 許可状態のときは「Push通知Off」のアイコンを表示
 キャッシュ優先のsw.jsだと更新ボタンでもキャッシュのまま、Cookieの中のサービスワーカーを削除

Service Workerキャッシュ戦略>保存日はindexedbに置き、HTMLの有効期限は1日にする
 ※参考まで、なおindexeddbは永続データで大きくなりすぎたら使用に応じて自動的に削られる仕様だったかと
https://qiita.com/tiwu_official/items/47e8a7c3e6f2d57816d7

https://techblog.asahi-net.co.jp/entry/2018/09/28/173705
受信する端末ごとに異なるメッセージを送るにはGoogle Firebaseが使われる様である

 トークンを発行し端末とトークンを紐付け配信サーバに記録
 配信サーバでメッセージを作り、個別トークンに対しメッセージ通知
  JSONを送るがトークンを持っているもののみ通知が発火?

Notifications APIを見てみよう
https://developer.mozilla.org/ja/docs/WebAPI/Using_Web_Notifications
https://developer.mozilla.org/ja/docs/Web/API/Push_API
https://developer.mozilla.org/ja/docs/Web/API/ServiceWorkerRegistration/pushManager

モバイルでなくPCへの通知自体はServiceWorkerが不要、下記2ステップでOK(ブラウザに許可を入れるのが必要)
 Notification.requestPermission(function(status) { 許可を取り
 var n = new Notification(theTitle,options); 通知を送る

カレンダーをサブカレンダー(o)化しPWAでオフライン対応(機内モード)
 キャッシュするよう指定しても現アクセス分の有効時間のキャッシュの影響か直ぐにはオフライン化はしないようだ(反映に~30分掛かることがある)
  一度オフライン時にアクセスしエラーが出た上、ネットワークが回復すると自動にキャッシュされる
   エラーを出さずに一度通常表示をするだけではキャッシュされなかった
   アンドオイドでは通知も来る(1:準備ができるとChromeでページが読み込まれます→2:ページを表示できます)
 ServiceWorker内ではLocalStorageはセキュリティを理由らしいが使えない
  IndexedDBは使えるらしいが、、、→使えんかった、よく分らん→ラッパー要るやろでOK
 SWをインスコしたディレクトリへのアクセスでSWが動く、SWJS自体へのアクセスではない
 PHPでJSを吐いてもOK js_serviceworker.phpとかでheaderをJavascriptとして

https://webtan.impress.co.jp/e/2019/08/26/33636
JavaScriptを使えば、ページをリロードせずにブラウザのURLバーの内容を変更できるのでSPAでも戻るが使える
history.pushState(null, "Page 2", "/page2.html");
https://webtan.impress.co.jp/e/2019/09/02/33637
Fetch APIを使用してリクエストをハイジャックしたりレスポンスを変更または改ざん出来る
https://qiita.com/propella/items/6500f76c9c1521878a6b
https://developers.google.com/web/fundamentals/primers/service-workers?hl=ja
SWが分かりやすい
ServiceWorker, Cache API を使用して 4万件のアセット永続化を試した話 | 株式会社ノックノート (knocknote.co.jp)

キャッシュを解析してどれ位まで保持してるか、URL等々も確認もできる
 if(status ==200 && ok){ //okはtrue/falseが入るが文字にはなれずboolean
キャッシュ削除もできるが、Indexeddbで管理をするし、SW1発目ではインスコだけで動作しない等で扱いは手間

Sync(まだ非標準)
通信がオフからオンに変わった時点で発火。バックグラウンドで何かを実施する、indexeddbにデータを貯めオンでサーバに送る等を行う
https://qiita.com/horo/items/28bc624b8a26ffa09621
Periodic background syncはメールクライアントの受信ボックス更新のように、バックグラウンドで定期的にタスクを実行
ユーザのIPを定期的に確認しトラックできる安全性、バッテリやリソースやギガ消費などの問題がある
AddtoHomeやサイトエンゲージメントが高いや普段使いのネットワーク等で発火が判断される
https://blog.jxck.io/entries/2020-04-23/periodic-background-sync.html

WORKBOX(google)のsyncは仕様が違う?分からん
エクスポネンシャルバックオフ(補足: 最大再試行回数に達するまで、指数関数的に増加する待機時間で操作を再試行する手法 – 1秒、2秒、4秒、8秒、16秒...とシステムに負担をかけない)を採用
syncイベントはユーザがアプリケーションから離れた時にも送られます
テスト時はインターネットを遮断するか(オフライン)、ウェブサーバーを落としてください。Chrome DevToolのOfflineモードは使用しないでください!Devtoolのofflineチェックボックスはページからのリクエストのみに影響があります。サービスワーカーのリクエストは成功してしまいます

/// 開発上の注意
FetchAPIは404や500エラーをthenで受け取れない
 JS送り側>サーバ側>JS受け と丁寧に開発を
  SWからDOMは弄れない→sync全体描画やpostMessageやnew Responseの検討?
JSONの値はダブルコーテーションで括る必要がある
 header("Content-type: application/json; charset=UTF-8");
 echo '{ "response": "no data" }';
JSONでレコード数がある場合は[]で括る必要がある
 echo '[{ "response": "1" },{ "response": "2" }';
PHPではPOSTデータを$_POSTで受け取れるのは「application/x-www-form-urlencoded」又は「multipart/form-data」のみ
 file_get_contents('php://input')で受け取る
 $contents = json_decode(file_get_contents('php://input'), true);
モバイルだとhttp://でアクセスしているかどうか分かりにくいが、https://でしか動作しない

/// mmm
キャッシュが強い(失敗すれば手動でCookie/Serviceworker削除、くせ強でユーザに古いページを見せ続けるかも)
 どの範囲をキャッシュするか、キャッシュページの案内方法(お気に入りに入れる?)をどうするか
 SinglePageAppなら枠だけキャッシュさせて後は外部JSでいけるが
  工夫を考える:転送、外部JS、IFRAME、AJAX、サーバサイド、Refer、new Response等々

データもキャッシュする場合は2パターンかな、Pros cons、データをIndexeddbに持つ形ならモバイルApp的SinglePageApp的
┏online
┃1)DLしたキャッシュを表示(最新情報が届かない、だが何をキャッシュしているか分かる、サブサイト化でバックアップ用途)
┃ 普段使わないとキャッシュ更新を忘れる、SWがDL中のものを反映し表示するのに時間が掛かる(時々転送やIFRAME系でDL?)
┃2)最新を表示、裏でDLを実施(最新を表示しているので通常利用できる、DL頻度を下げたりProxy/キャッシュで動作が分からないところがある?)
┃ 何をキャッシュしているか不明、(バックアップサイトを持たず一体で便利だが、頻繁にキャッシュ全更新しがち、動作不明なことがある)
┗offline
 キャッシュを表示

Notification API(デスクトップ通知)
デスクトップ通知スケジューラー (bangboo.com)
Cache API(スケジュールのオフライン化)
https://pimpub.jpn.org/aaaaaa/o/install.php
Service worker API - Sync(バックグラウンド同期)
オフライン予約システム (bangboo.com)

Posted by funa : 06:00 PM | Web | Comment (0) | Trackback (0)


April 1, 2020

G Suite
https://www.softbank.jp/biz/cloud/google/gsuite/
中途半端に移行するよりGsuite強制だと社員が勝手に使うシャドーITをなくせる
影響力のある社員の抵抗がないように、部長の関心協力→Topからのメッセージ
 デモを実施する(利点、コラボレーション、使い方)
戦略・組織の把握>パイロットユーザ(全社員の5%をGoogleガイド)>エバンジェリスト公募>全社
 画面や機能がどんどん変わる、また簡単になっていく、カチッと決め打ちはしにくい
 Gmail (アーカイブして検索で、容量無制限)
 カレンダー (会議スケジューリングのお勧めがある)
 Hangouts Chat (1to1かグループでチャット、共同編集、Voiceがあれば電話も、Botも)
 ハングアウトMeet (ビデオ通話)
 ドライブ (同時編集ができる、ここでドキュメントを作ると相互最新更新)
  ドキュメント (Word/PDF/html/txt等読込書出、AIで画像やグラフやデザインをクリックだけで、無制限変更履歴)
  スプレッドシート (Excelを変換して使う等 https://support.google.com/docs/answer/9331167?hl=ja )
  スライド (ブラウザでプレゼンテーション、PPT等から変換可、オフライン化も可だが問題がありそう)
 Currents (Google+社内SNS、フォロー、投稿、サークル、コミュニティ)
 フォーム (アンケート、クイズ/テスト、連絡先を含め申し込み欄)
 Keep (メモ:音声入力や写真も、リマインダー、Gmailユーザ共有)
 Jamboard (ホワイトボード、複数個所やマルチデバイスやGsuite連携)
 サイト (一般公開HP、イントラ)
 Apps script (aka GAS、マクロ、https://tonari-it.com/google-apps-script-manual/ )
 Cloud Search (Gsuite以外にもコネクタでAWSやMS系、Jira、Sap、Salesforce等も検索可)
 Vault (元が消されても全データ保存されている、管理者)
 管理コンソール (ユーザグループ管理/SSO/MFA、監査ログ、MDM、セキュリティ系レポート、移行ツール/API/Oauth/OpenID)
https://gsuite.google.co.jp/intl/ja/features/ 無料試用14日間

///Google Admin 管理コンソール
上ナビのタスクにダウンロード等がある
"ダッシュボード" ?
"ユーザ"でリストをCSVでDLし、一括アップロードもできる
 メールアドレス確認のメールが来ていた
"グループ"はグループオーナ/管理者/メンバー/組織全体/外部でアクセス管理
"組織部門"をツリー状に作成できる
"リソース管理"でビルディング/会議室/設備等々を設定
 カレンダーでの会議室の自動予約キャンセル(使われていない会議室が解放)
"ディレクトリ設定"で連絡先の共有、外部ディレクトリ共有の設定
"デバイス管理"でモバイル/Chromeデバイス/ブラウザ/Googleミーティングハード/エンドポイント/Jamboard
 よく分からない
"アプリ"で全ユーザONかOffか/SAMLアプリの追加
"セキュリティ"で2段階認証/アラートセンタ/ルール/PWポリシー/安全性の低いアプリへ接続/PW忘れのアカウント復元/PW強度監視/従業員IDでログイン時本人確認/3rdパーティSSO設定/Android用EMMプロバイダトークン/高度な保護機能/Context aware access/セッション時間/Cloud ConsoleとCloud SDKのセッション/OAuthのユーザーデータへのACL/API許可
"レポート" ?
"お支払い"で課金の管理、ユーザ数x費用/ドメイン登録費用/G Suite Enterprise/Voice Standard/Cloud Identity
"会社プロフィール"で管理者ID/サポート連絡先/タイムゾーン/即時か計画リリース/Googleからのお知らせ/ロゴ設定/追加ストレージ/コンプラ連絡先/データリージョン米か欧/会社自体のアカウント/カスタムURL
"管理者ロール"で特権/ヘルプデスク/サービス/ユーザ/モバイル等の権限者を設定
"ドメイン"でドメイン契約の設定/他のドメインで使用するためのドメインのホワイトリスト
"データ移行"でO365/Exchange等のメール/カレンダ/連絡先を移行できる
"サポート"でチャットできる
どうやってサポート?リモート?ファイル共有はできるのか?
ファイルが保存されているかどうか分かりにくい
保存が遅い場合も、待ってもう一度確認、全ての操作が記録されているはず

Gmailヘルプ https://support.google.com/?
各アプリでもヘルプ?があるので確認できる、FAQみたいなのも表示される
設定ギア>ここでほぼ設定している
Gmail
 迷惑メール/削除したメールは、[ゴミ箱] に 30 日間保存され、その後完全に削除
 メールはスレッドにまとめられ[削除] するとスレッド全体が削除
 Gmail で使用できる検索演算子 https://support.google.com/mail/answer/7190?hl=ja
 不要ラベル、Keyラベル等を付けて移動してもいいかも?
マイドライブ
 組織内でもグループ内でもWeb公開もURLでも編集やコメントも細かく共有設定ができる
 ファイルとしてDL、それをマイドライブにアップしG suite化できる
ドキュメント
 提案モードで修正→ツール>編集の提案の確認orチェック で承認ができる
スライド
 プレゼンター(マウス↓でメニュー表示、ノートや質問)、オンラインプレゼンは不可
コレクション
 +のURLのみ集められる?モバイルやPCは駄目かも
Keep
 メモの共有を外部にするとメールが送信
カレンダー
 デスクトップ通知は各種許可設定があり調べよ、Chromeの機能 chrome://flags/#enable-native-notifications

何をサルベージできるのか不明:メールログ、Vaultで削除ファイルは見れる?

G-suiteはオフラインでも使える
 管理者側設定:許可設定
 ユーザ側設定:オフライン許可設定

O365とのプロコン
 G-suiteは少し安い、使用が簡単だがプア、共有や共同編集に優位、オフラインで機能が弱い

■Gmail 自動振り分け(迷惑メールのブロック)
設定ギア>全て表示>フィルタ関連のタブ
含むの項目使いやすい(特殊文字を省いて半角スペース区切りでキーワード網羅がいい、subject等は括弧や特殊文字で思うように行きにくい)
 各項目間はAnd条件:あいうえお かきくけこ
 各項目でORやAND指定ができる:あいうえお OR かきくけこ
 覚えておきたいGmailの絞り込み条件指定方法|フィルタ利用時には検索演算子を使おう (keizokuma.com)
 フィルタや自動化ルールで正規表現を使用する - 検索広告 360 ヘルプ (google.com)
 gmailのフィルタ機能は超便利 - 愚鈍人 (hustle.ne.jp)

■Google spreadsheet
Googleスプシのvlookupは一番左の列のみしか検索しない仕様

■Google Form
回答で保存先スプレッドシートを指定できる https://www.infact1.co.jp/staff_blog/webmarketing/43713/

■GAS
doPostとdoGetが使えるがほとんど何もできない? GASをWeb公開して実行(doPostとdoGet) | アンクルエンジニアの気づき (uncle-atsushi.com)

■Zapier
IFTTTみたいなやつ、アプリ間連携が簡単にできる
ドキュメントがあるのかないのか、全然見つからないので自分で検証が必要、簡単だが手間
少し値を変えれば保存されるので弄る前にコピーをしコピーを弄る
Zap上のGoogleSpreadsheetのIDは行番号を含む行作成時のユニークID、他の行が削除され行番号がずれるとIDが取得できなくなる、RowID(他の行が削除されても参照が維持される)かRowNumber(行番号で再度他のカラムで検索すれば新たに参照可)を使いたい

■Slack
ChannelにJoin
スレッド返信(@メンションを付けた方がいい?)
リアクションでアイコン返信
メッセージ編集や削除
ブックマーク
ダイレクトメッセージ:
 新規メッセージで相手を選んで送信
 @メンションを付けてチャンネルに投稿するメッセージとは異なる
```で挟むと囲み線、`で囲むと囲み線で赤字
 うまくいかんときは文字を選択し右クリックで</>□等で
>>>を付けると引用
検索オプション
 in:channel from:userid
ナビを常時表示:サイドバーopen(?)
https://dekiru.net/category/service-software/slack/

Posted by funa : 12:01 AM | Web | Comment (0) | Trackback (0)


Navi: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11  >
PhotoGallery


TWITTER
Search

Mobile
QR for cellphone  QR for smart phone
For mobile click here
For smart phone click here
Popular Page
#1Web
#2Hiace 200
#3Gadget
#4The beginning of CSSレイアウト
#5Column
#6Web font test
#7Ora Ora Ora Ora Ora
#8Wifi cam
#9みたらし団子
#10Arcade Controller
#11G Suite
#12PC SPEC 2012.8
#13Javascript
#14REMIX DTM DAW - Acid
#15RSS Radio
#16Optimost
#17通話SIM
#18Attachment
#19Summer time blues
#20Enigma
#21Git
#22Warning!! Page Expired.
#23Speaker
#24Darwinian Theory Of Evolution
#25AV首相
#26htaccess mod_rewite
#27/// BANGBOO BLOG /// From 2016-01-01 To 2016-01-31
#28竹書房
#29F☆ck CSS
#30Automobile Inspection
#31No ID
#32Win7 / Win10 Insco
#33Speaker
#34Arcade Controller
#35Agile
#36G Suite
#37Personal Information Privacy Act
#38Europe
#39Warning!! Page Expired.
#40GoogleMap Moblile
#41CSS Selectors
#42MySQL DB Database
#43Ant
#44☆od damnit
#45Teeth Teeth
#46Itinerary with a eurail pass
#47PHP Developer
#48Affiliate
#49/// BANGBOO BLOG /// From 2019-01-01 To 2019-01-31
#50/// BANGBOO BLOG /// From 2019-09-01 To 2019-09-30
#51/// BANGBOO BLOG /// On 2020-03-01
#52/// BANGBOO BLOG /// On 2020-04-01
#53Windows env tips
#54恐慌からの脱出方法
#55MARUTAI
#56A Rainbow Between Clouds‏
#57ER
#58PDF in cellphone with microSD
#59DJ
#60ICOCA
#61Departures
#62Update your home page
#63CSS Grid
#64恐慌からの脱出方法
#65ハチロクカフェ
#66/// BANGBOO BLOG /// On 2016-03-31
#67/// BANGBOO BLOG /// From 2017-02-01 To 2017-02-28
#68/// BANGBOO BLOG /// From 2019-07-01 To 2019-07-31
#69/// BANGBOO BLOG /// From 2019-10-01 To 2019-10-31
#70/// BANGBOO BLOG /// On 2020-01-21
#71Bike
#72Where Hiphop lives!!
#73The team that always wins
#74Tora Tora Tora
#75Blog Ping
#76無料ストレージ
#77jQuery - write less, do more.
#78Adobe Premire6.0 (Guru R.I.P.)
#79PC SPEC 2007.7
#80Google Sitemap
#81Information privacy & antispam law
#82Wifi security camera with solar panel & small battery
#83Hope get back to normal
#84Vice versa
#85ハイエースのメンテ
#86Camoufla
#87α7Ⅱ
#88Jack up Hiace
#89Fucking tire
#90Big D
#914 Pole Plug
#925-year-old shit
#93Emancipation Proclamation
#94Windows env tips
#95Meritocracy
#96Focus zone
#97Raspberry Pi
#98Mind Control
#99Interview
#100Branding Excellent
Category
Recent Entry
Trackback
Comment
Archive
<     December 2021     >
Sun Mon Tue Wed Thi Fri Sat
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Link