M1 Macで ECSにSpring bootのREST APIをデプロイしようとしたけど失敗した
環境
macOS Big Sur M1
デプロイするサンプルアプリ
/greeting
でhello worldを返すだけのSpring-bootのREST API
ECS Fageteへのデプロイ
copilotを使ってデプロイする
# homebrewでインストール $ brew install awscli # 確認 $ aws --version aws-cli/2.3.5 Python/3.9.7 Darwin/20.6.0 source/arm64 prompt/off
$ aws configure AWS Access Key ID [None]: アクセスキー AWS Secret Access Key [None]: シークレットアクセスキー Default region name [None]: リージョン Default output format [None]:
Copilotインストール
$ brew install aws/tap/copilot-cli # 確認 $ copilot -v copilot version: v1.12.0
Copilotで環境作成
$ copilot init What would you like to name your application? [? for help] greeting-app #デプロイするアプリケーション名を入力 Application name: greeting-app Which workload type best represents your architecture? [Use arrows to move, type to filter, ? for more help] # 構築したい構成を選びます。 Request-Driven Web Service (App Runner). > Load Balanced Web Service (Internet to ECS on Fargate) Backend Service (ECS on Fargate) Worker Service (Events to SQS to ECS on Fargate) Scheduled Job # LB込みでバックエンドサービスをデプロイしたいので Load Balanced Web Serviceを選択 Which Dockerfile would you like to use for greeting-app? [Use arrows to move, type to filter, ? for more help] # Dockerfileを選択 > greeting/Dockerfile Which port do you want customer traffic sent to? [? for help] (80) #ポートを選択 Would you like to deploy a test environment? [? for help] (y/N) y # テスト環境としてデプロイするか選択
動かない..
アプリケーションのヘルスチェックで落ちて動かない。。
✔ Created ECR repositories for service greeting-app.. All right, you're all set for local development. Deploy: Yes ✔ Linked account 680356542845 and region ap-northeast-1 to application greeting-app.. ✔ Proposing infrastructure changes for the greeting-app-test environment. - Creating the infrastructure for the greeting-app-test environment. [create complete] [92.1s] - An IAM Role for AWS CloudFormation to manage resources [create complete] [27.2s] - An ECS cluster to group your services [create complete] [8.8s] - Enable long ARN formats for the authenticated AWS principal [create complete] [2.0s] - An IAM Role to describe resources in your environment [create complete] [23.8s] - A security group to allow your containers to talk to each other [create complete] [5.7s] - An Internet Gateway to connect to the public internet [create complete] [18.1s] - Private subnet 1 for resources with no internet access [create complete] [19.0s] - Private subnet 2 for resources with no internet access [create complete] [19.0s] - Public subnet 1 for resources that can access the internet [create complete] [19.0s] - Public subnet 2 for resources that can access the internet [create complete] [19.0s] - A Virtual Private Cloud to control networking of your AWS resources [create complete] [15.5s] ✔ Created environment test in region ap-northeast-1 under application greeting-app. Environment test is already on the latest version v1.6.1, skip upgrade. Building your container image: docker build -t 680356542845.dkr.ecr.ap-northeast-1.amazonaws.com/greeting-app/greeting-app --platform linux/amd64 /Users/masami/greeting -f /Users/masami/greeting/Dockerfile [+] Building 2.2s (7/7) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 36B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/openjdk:11-jdk-slim 2.1s => [internal] load build context 0.0s => => transferring context: 117B 0.0s => [1/2] FROM docker.io/library/openjdk:11-jdk-slim@sha256:ad41c90d47fdc84fecb3bdba2deb38e378bbde1d7f5a378ba0964c466b23dbca 0.0s => CACHED [2/2] COPY build/libs/greeting-0.0.1-SNAPSHOT.jar app.jar 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:658315566f443e0dc2795c5d605d29ad71f4f9e512469135bc4c908425447ade 0.0s => => naming to 680356542845.dkr.ecr.ap-northeast-1.amazonaws.com/greeting-app/greeting-app 0.0s Login Succeeded Using default tag: latest The push refers to repository [680356542845.dkr.ecr.ap-northeast-1.amazonaws.com/greeting-app/greeting-app] 408e323e553a: Pushed 007baf3afc22: Pushed 62763247decf: Pushed 2bf2b8c78141: Pushed e8b689711f21: Pushed latest: digest: sha256:09e11c29227fac3c7c730af1a9eb59fb7950d2003b2a984b6d7e790b452e8e94 size: 1372 ✔ Proposing infrastructure changes for stack greeting-app-test-greeting-app - Creating the infrastructure for stack greeting-app-test-greeting-app [create complete] [376.6s] - Service discovery for your services to communicate within the VPC [create complete] [0.0s] - Update your environment's shared resources [update complete] [181.1s] - A security group for your load balancer allowing HTTP and HTTPS traffic [create complete] [6.6s] - An Application Load Balancer to distribute public traffic to your services [create complete] [152.3s] - An IAM Role for the Fargate agent to make AWS API calls on your behalf [create complete] [27.6s] - A CloudWatch log group to hold your service logs [create complete] [3.3s] - An ECS service to run and maintain your tasks in the environment cluster [create complete] [91.6s] Deployments Revision Rollout Desired Running Failed Pending PRIMARY 2 [in progress] 1 1 1 0 ✘ Latest failure event - (service greeting-app-test-greeting-app-Service-bfQWCpWYD0kA) (port 80 ) is unhealthy in (target-group arn:aws:elasticloadbalancing:ap-northe ast-1:680356542845:targetgroup/greet-Targe-RCG2FPBWXXAQ/3d66f91ea0a3cf a1) due to (reason Health checks failed). - A target group to connect the load balancer to your service [create complete] [4.0s] - An ECS task definition to group your containers and run them on ECS [create complete] [3.5s] - An IAM role to control permissions for the containers in your tasks [create complete] [23.6s]
調べたところM1 macだとデプロイで死ぬらしい(Dockerのアーキテクチャが異なるため).
copilot init
だと環境構築からアプリケーションのデプロイまで一括でやってくれるが、私の環境だとデプロイは別の方法で回避しないといけない。
以下コマンド等で個別にステップを実施できる。
$ copilot env init $ copilot svc init $ copilot svc deploy # CodePipelineも作れる $ copilot pipeline init $ copilot pipeline update
アプリのデプロイはまたの機会に実施したい。
作成した環境のお片付け
# 作成したアプリケーションの確認 $ copilot app ls greeting-app # 削除 $ copilot app delete --name greeting-app Sure? Yes
まとめ
起動まではいかなかったが、お手軽にWebサービスに必要な環境一式を揃えることができる便利ツールであることはわかった。
ネットワークの定義やIAM定義など、結構手間がかかることもやってくれるのは個人的にありがたい。
私が関わる案件では環境がterraformで整備されていることが多いのであまりお世話にならないが、個人でサクッとサービスを立ち上げるには打って付けだと思う。
一方で込み入った環境設定をしたい場合はCloudFormationの知識が必要となってくるので人によっては学習コストが発生する。
他にも細かい制約はありそうですが、今回はここまで。
【Laravel】eloquent を使用していて、auto increment falseが効かなかった件
記事にするほどでもないが、メモがてら
事象
eloquentだとデフォルトでidがauto incrementですが、プレフィックスを付けたくてアプリ側でidを振る必要がでてきたのでauto incrementをfalseにしたが、反映されなかった。
環境
Laravel Framework 6.5.0
原因、対応
モデルの$fillableにidいれてなかったのでアプリ側で作ったIDがDBに反映されなかった。
$fillableにidを追加すると動作した。
エラーが返してくれれば良いのにauto incrementで入れてくれるんだね。
【Vue】filepond Postパラメータ渡し方
はじめに
filepondというライブラリを使用してファイルアップロード機能を実装していたが、postパラメータをサーバー側に渡すところで少し躓いたのでメモ。
環境
vue@2.6.11
vue-cli 2.9.6
Laravel Framework 6.5.0
filepond@4.9.5
やったこと
filepond インストール
filepondの導入と基本的な使い方はいろいろと記事があるので割愛。
参考にさせて頂いたサイト
pqina.nl
File metadata プラグインインストール
公式ページのFile metadataの項目を参考にしてインストール
npm i filepond-plugin-file-metadata --save
vueファイル ユーザーIDをPostで送る
<template> <file-pond :server="url" allowRevert="false" instantUpload="false" /> </template> <script> import vueFilePond, { setOptions } from "vue-filepond"; import "filepond/dist/filepond.min.css"; /* Plugin */ import FilePondPluginFileMetadata from "filepond-plugin-file-metadata"; const FilePond = vueFilePond( FilePondPluginFileMetadata ); export default { components: { FilePond }, data() { return { url: "http://localhost:8000/api/fileupload", userId: 1, } }, /** 中略 */ mounted() { //ここでパラメータをセット setOptions({ fileMetadataObject: { userId: this.userId } }); } ...
サーバー側(php)
use Illuminate\Http\Request; public function postFileUpload(Request $request) { $input = json_decode($request->input('filepond')); //ユーザーID取得 $userId = $input->userId; //なんらかの処理 }
終わりに
とりあえず動くが、ファイルのメタデータとしてデータを渡している?のは違和感がある。 良い方法があれば教えていただければうれすぃ
【Laravel/Vue】postのパラメータの書き方ミスって419エラーと勘違いした話
はじめに
現在Laravel/Vue.jsでマッチングサイトを作っており、その際認証周りの経験が浅くしょうもないところで詰まってしまった話。
環境
vue@2.6.11
Laravel Framework 6.5.0
Firefox 73.0.1
起こったこと
php/laravel/vueを使ったSPAのマッチングサイトを作っており、お気に入り機能実装時にaxiosのpostメソッドを追加。
別の部分に書かれてるgetメソッドを一旦コピペしてpostに変え、パラメータを以下のように修正しました。
※コードはサンプル。
#コピペ元 getBandList() { axios.get("/matching", { params: { offset: this.offset, limit: this.limit } }) .then(res => { this.records = res.data.recordList; }); }, #コピペ後 addFavoriteList() { axios.post("/addFavorite", { params: { //※ここが間違い hoge: 'hoge', fuga: 'fuga', } }) .then(res => { this.message = res.data }); }, #コントローラー class FavoriteListController extends Controller { public function addFavorite(Request $request) { $id = Auth::id(); $hoge = $request->input('hoge'); $fuga = $request->input('fuga'); //なにかしらの処理 .... } #web.php Route::group(['middleware' => 'auth'], function () { Route::get('/addFavorite', 'FavoriteListController@addFavorite'); ... }
getメソッドをコピッたのでparamsを消し忘れており、500エラーが発生。問題はここから。
firefoxのデベロッパーツールで確認しており、ネットワークから500の部分をダブルクリックして、別タブでエラーの内容を確認しようとしました。
すると、419 Page Expired が。
ここで、419エラーと勘違いし、CSRF token関連のエラー記事を参考に試行錯誤を繰り返してしまいました。
※ちなみに、元のネットワーク画面の応答にサーバーのエラー内容ががっつりのってますw
色々と試してるうちに、他のpostメソッドでもネットワークをダブルクリックすると419ページに飛ぶことから、別タブで開いたことがCSRF token認証に失敗の原因であることに気が付きました。
ちなみに、上記操作をchromeで行うと500エラーの内容が表示されました。
firefoxではネットワークから別タブで開いた場合 token情報を持っていませんでしたが、chromeはtoken情報を持っていたため419が発生せず。
ブラウザ間でこういう違いもあるんですね。 ( ̄- ̄)フーン ナルホド
終わりに
ちゃんとコンソール見ましょう。あと疲れたら早く寝ましょう。
【NGS】velvet・SPADesを使ったアセンブル
OS Ubuntu 18.04.2
conda 4.7.11
velvet インストール
# Anacondaでインストール conda install -c bioconda velvet
アセンブル (k-mer 21)
k-mer は奇数しか指定できないので注意。
#処理するデータの準備。(fastaでもok) velveth vel_21 21 -shortPaired -fastq **.fastq #コンティグ作成 velvetg vel_21 -ins_length 300 -read_trkg yes -amos_file yes #結果ファイル less vel_21/Log
SPADes インストール
# Anacondaでインストール conda install -c bioconda spades
アセンブル (kmer 21 ~ 55)
spades.py -k 21,33,55,77 --careful --only-assembler **.fastq -o spades_output
isucon手順まとめ
isucon9に出場し予選落ちしました。
isucon7の問題を多少練習したので(isucon8もちょっと)、チーム内のwikiが消えても大丈夫なようその時の手順をメモします。
自分用なので雑。
初期設定
alp 導入
#ダウンロード wget https://github.com/tkuchiki/alp/releases/download/v0.3.1/alp_linux_amd64.zip unzip alp_linux_amd64.zip #インストール sudo install ./alp /usr/local/bin #nginxの設定ファイルを修正 sudo vim /etc/nginx/nginx.conf #設定ファイルのhttp {の部分に以下の内容を追加します。 http { log_format ltsv "time:$time_local" "\thost:$remote_addr" "\tforwardedfor:$http_x_forwarded_for" "\treq:$request" "\tmethod:$request_method" "\turi:$request_uri" "\tstatus:$status" "\tsize:$body_bytes_sent" "\treferer:$http_referer" "\tua:$http_user_agent" "\treqtime:$request_time" "\truntime:$upstream_http_x_runtime" "\tapptime:$upstream_response_time" "\tcache:$upstream_http_x_cache" "\tvhost:$host"; access_log /var/log/nginx/access.log ltsv; } #元のアクセスログを削除し、リロード sudo rm /var/log/nginx/access.log && sudo systemctl reload nginx #ベンチ実行 /home/isucon/torb/bench/bin/bench -data=/home/isucon/torb/bench/data -remotes=localhost -output=result.json #alp確認 alp -f /var/log/nginx/access.log alp --sum -f /var/log/nginx/access.log
netdata インストール (使わんかったけど一応)
#ワンライナーで起動までしてくれる。 bash <(curl -Ss https://my-netdata.io/kickstart.sh) all --dont-wait #firewall ポート穴あけ firewall-cmd --zone=public --add-port=19999/tcp --permanent systemctl reload firewalld.service #ブラウザで確認 http://127.0.0.1:19999/ #停止 systemctl stop netdata #起動 systemctl start netdata
slow-log出力
MYSQL系の設定ファイルである/etc/my.cnfに以下のように設定を追加する
[mysqld] # 以下の3行を追加する slow_query_log slow_query_log_file = mysql-slow.log long_query_time = 0.5 このように設定すると、/var/lib/mysql配下にmysql-slow.logが出力されるようになるはず サービスの再起動を忘れずにね systemctl restart mariadb
pt-query-digestのインストール
以下のコマンドでインストールできる! #cent0s yum install http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm yum install percona-toolkit #ubuntu wget https://www.percona.com/downloads/percona-toolkit/3.0.10/binary/debian/xenial/x86_64/percona-toolkit_3.0.10-1.xenial_amd64.deb sudo apt-get install gdebi sudo gdebi percona-toolkit_3.0.10-1.xenial_amd64.deb あとは上記で出力したスロークエリログを解析する pt-query-digest /var/lib/mysql/mysql-slow.log
mysql ダンプ
サーバ内の初期データをdumpにする
以下のコマンドでisubataテーブルだけを対象にdumpを作成する mysqldump --single-transaction -u isucon -p isubata > /tmp/isubata_init.dump 出力したdumpを適当にWinSCPとかでローカルに持ってくる
サービスをPythonに変更する
# サービスを停止する systemctl stop torb.perl.service # サーバ起動時に起動するサービスから除外する systemctl disable torb.perl.service # サービスを開始する # sudo systemctl start torb.go.service sudo systemctl start torb.python.service systemctl enable torb.python.service
DB回り改善
インデックス確認、作成
#テーブル名、カラム名などは適宜置き換えてください。 mysql>explain SELECT COUNT(*) as cnt FROM message WHERE channel_id = 10 #type が ALL/indexだと遅い。 #インデックス追加 ※カラムの順番重要 mysql>ALTER TABLE message ADD INDEX index_name(channel_id, id); #インデックス削除※間違った時用 mysql>ALTER TABLE message DROP INDEX index_name; https://qiita.com/katsukii/items/3409e3c3c96580d37c2b http://tech.aainc.co.jp/archives/4634
外部mySQLへの接続
#mysqlのデフォルトポート3306の通信を許可する sudo ufw allow 3306 ※firewallが無効になっていたら無視。 mysqld.cnfの編集 sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf #bind-addressをコメントアウトする。 bind-address = 127.0.0.1 #rootユーザはどのIPからもアクセス可能に mysql> grant all privileges on [データベース名].* to root@"%" identified by 'パスワード' with grant option #外部mySQLへの接続が確認できたら、app側のsqlへの接続設定も変更する。
nginx周り改善
#ヘッダーへCache-Control追加 #/etc/nginx/sites-available/default server{ add_header Cache-Control public; } https://qiita.com/syou007/items/3e2d410bbe65a364b603 #ロードバランサ振り分け処理 #/etc/nginx/nginx.conf 追記 http { upstream degumainux.com { #ip_hash; #least_conn; server [ip]:[port]; server [ip]:[port]; } server { location / { proxy_set_header Host $http_host; proxy_pass http://degumainux.com; } } }
カーネル回り
#somaxconn数変更 #確認 sysctl net.core.somaxconn #somaxconn書き換え(一時的) sysctl -w net.core.somaxconn=1024 #somaxconn書き換え(永続化) #/etc/sysctl.confに追加 net.core.somaxconn = 1024 #リロード sysctl -p http://tetsuyai.hatenablog.com/entry/20111220/1324466655
dbrp、uniprotのapiをつかってpythonでデータ取得
自分用メモ ちょっと修正
dbrp_data_get.py
import json import os.path import sys import requests # 引数に指定したゲノム情報のアクセッション番号を検索し、accessibilityAPIの値からfastaファイルを取得するスクリプト。 # python dbrp_get.py [input_list] def main(): args = sys.argv file_name = args[1] print(file_name) url = 'https://www.nite.go.jp/nbrc/dbrp/api/dataget' data_format = '.zip' params = {'data_id': file_name} response = requests.get(url, params=params) dict = response.json() data_body_str = dict['result']['data_body'] data_body = json.loads(data_body_str) accessibility_api = data_body['@graph'][0]['DataDownload']['accessibilityAPI'] url2 = 'https://www.nite.go.jp/nbrc/dbrp/api/fileget' params2 = {'file_id': accessibility_api} download_data = requests.get(url2, params=params2) if not os.path.exists('./data/dbrp/'): os.makedirs('./data/dbrp/') with open('./data/dbrp/' + file_name + data_format, 'wb') as f: f.write(download_data.content) print("finish!") if __name__ == '__main__': main()
uniprot_data_get.py
import requests import os.path import sys def main(): # 引数に指定したアクセッション番号のリストを指定し、uniprotのAPIでデータを取得するスクリプト。 # python uniprot_data_get.py [input_list] args = sys.argv list_name = args[1] base_url = 'https://www.uniprot.org/uniprot/' format = '.fasta' list = open(list_name, 'r') if not os.path.exists('./data/uniprot/'): os.makedirs('./data/uniprot/') lines = list.readlines() for line in lines: print(line) accession_id = line.rstrip('\n') url = base_url + accession_id + format response = requests.get(url) with open('./data/uniprot/' + accession_id + format, 'wb') as f: f.write(response.content) print("finish!") if __name__ == '__main__': main()