バックエンドエンジニア

【開発体制】 アジャイルな開発体制としてスクラムを採用 【開発環境】 □言語:PHP(フレームワーク:FuelPHP)□環境:Linux(AWS EC2 ), Apache □DB : MySQL□バージョン管理:Git, GitHub□メール配信 : AWS SES□画像サーバ: AWS S3□CDN : AWS CloudFront□キャッシュ : AWS ElasticCache□その他 : RDS, … 続きを読む

Amazon ECS Adds New Endpoint to Access Task Metrics and Metadata

この記事に対して2件のコメントがあります。コメントは「 記事中の https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint.html によると、ECS Agent 1.17.0 からの機能。1.17.0 は本日リリースされたばかり( https://github.com/aws/amazon-ecs-agent/releases/tag/v1.17.0 )。 続きを読む

【開催報告】AWS Media Services ローンチセミナー | Amazon Web Services ブログ

なんで半角じゃだめなん? ていうか、システムで自動変換してくれんの? 登録ボタン押した後にこれ出るのせいで、途中で会員登録やめたのいっぱいあるわ。 プログラムのネーミングに迷ったら GitHub でコード検索すると参考になる説 – Qi… 171 users · qiita.com. TL;DR プログラムのネーミングで迷ったら GitHub で … 続きを読む

AWS Lambdaでkintoneアプリの簡易自動バックアップを作ってみた その1(フォーム設計情報とレコードの取得)

kintone自体はアプリケーションを非常に簡単に作成できるのですが、そのバックアップ、となると有償の製品を購入するか、あるいは手動で実施する、というのが現状です。

そこで、有償のバックアップとまでは行かなくても、簡易的なバックアップの仕組みを作れないか、試してみました。

ゴール

とりあえず以下の条件をゴールとします。

  1. バックアップ対象は「フォームの設計」と「データ一式」
  2. バックアップは自動で定期的に実施される
  3. 必要であればリストアの仕組みも作る

バックアップのための仕組み

・フォームの設計情報をバックアップ
 →フォーム設計情報取得
・データ一式のバックアップ
 →第10回 kintone REST APIを利用したレコード取得

これらをAWS Lambda(Python 3)上から呼び出せるように実装します。リストアもjson形式で対応できそうなので、上記のページの通りの結果が得られればバックアップとしては問題なさそうです。

処理対象

こんな感じの備品在庫管理(既成品)を利用します。

スクリーンショット 2018-01-28 16.28.42.png

実装

前処理

色々と準備が必要なので、最初に実施します。

KINTONE_BASE_URL = os.environ['KINTONE_URL']
KINTONE_FORM_BASE_URL = os.environ['KINTONE_FORM_BASE_URL']
URL = KINTONE_BASE_URL.format(
    kintone_domain=os.environ['KINTONE_DOMAIN'],
    kintone_app=os.environ['KINTONE_APP']
)
FORM_URL = KINTONE_FORM_BASE_URL.format(
    kintone_domain=os.environ['KINTONE_DOMAIN'],
    kintone_app=os.environ['KINTONE_APP']
)
HEADERS_KEY = os.environ['KINTONE_HEADERS_KEY']
API_KEY = os.environ['KINTONE_API_KEY']

S3_BUCKET = os.environ['S3_BUCKET']
S3_OBJECT_PREFIX = os.environ['S3_OBJECT_PREFIX']

s3_client = boto3.client('s3')

全レコードの取得

こんな感じでQueryに何も指定しない全件取得を行います。

def get_all_records(headers):
    query = u''

    response_record = requests.get(URL + query , headers=headers)
    return json.loads(response_record.text)

フォーム設計情報取得

フォームは前述のページを参考にこのような実装になります。

def get_form_info(headers):

    response_record = requests.get(FORM_URL, headers=headers)
    return json.loads(response_record.text)

取得したデータをS3にバックアップとして保持

botoライブラリを利用して、tmpフォルダに一時的に作成したファイルをS3にアップロードします。

def put_data_to_s3(contents):
    date = datetime.now()
    date_str = date.strftime("%Y%m%d%H%M%S")
    tmp_dir = "/tmp/"
    tmp_file = S3_OBJECT_PREFIX + "_" + date_str + ".json"

    with open(tmp_dir + tmp_file, 'w') as file:
        file.write(json.dumps(contents, ensure_ascii=False, indent=4, sort_keys=True, separators=(',', ': ')))

    s3_client.upload_file(tmp_dir + tmp_file, S3_BUCKET, tmp_file)

    return True

上記を呼び出し側メソッド

今まで作成したきた部品をつなぎ合わせます。それぞれレコード一覧とフォーム設計情報を一つのJSONファイルにまとめる様に実装しています。

def run(event, context):

    headers = {HEADERS_KEY: API_KEY}
    record_data = get_all_records(headers)
    records = record_data['records']

    form_data =get_form_info(headers)
    forms = form_data['properties']

    result = {
        "records": records,
        "properties": forms
    }

    return put_data_to_s3(result)

(おまけ)環境変数はステージごとに切り替えるように実装

クラメソさんの記事を参考に、ステージごとに環境変数を切り替えられるようにしています。

serverless.yml
service: aws-kintone-backup

provider:
  name: aws
  runtime: python3.6
  region: us-east-1
  stage: ${opt:stage, self:custom.defaultStage}
  environment:
    KINTONE_URL: https://{kintone_domain}/k/v1/records.json?app={kintone_app}
    KINTONE_FORM_BASE_URL: https://{kintone_domain}/k/v1/form.json?app={kintone_app}
    KINTONE_HEADERS_KEY: X-Cybozu-API-Token
custom:
  defaultStage: dev
  otherfile:
    environment:
      dev: ${file(./conf/dev.yml)}
      prd: ${file(./conf/prd.yml)}

functions:
  run:
    handler: handler.run
    environment:
      KINTONE_DOMAIN: ${self:custom.otherfile.environment.${self:provider.stage}.KINTONE_DOMAIN}
      KINTONE_API_KEY: ${self:custom.otherfile.environment.${self:provider.stage}.KINTONE_API_KEY}
      KINTONE_APP: ${self:custom.otherfile.environment.${self:provider.stage}.KINTONE_APP}
      S3_BUCKET: ${self:custom.otherfile.environment.${self:provider.stage}.S3_BUCKET}
      S3_OBJECT_PREFIX: ${self:custom.otherfile.environment.${self:provider.stage}.S3_OBJECT_PREFIX}
dev.yml
KINTONE_DOMAIN: xxxxxx.cybozu.com
KINTONE_API_KEY: XXXXXXXXX
KINTONE_APP: XXX
S3_BUCKET: XXXXXX
S3_OBJECT_PREFIX: XXXXXX

slsコマンドでアップロードをする際に--stageオプションを指定する必要があります。(デフォルトはdev

実行してみる

さて、それぞれ環境変数を指定して実行してみます。無事S3にファイルが出力されました。中身も無事出力されています。(コンテンツが長いからここには載せないけど)

スクリーンショット 2018-02-05 22.08.06.png

AWS Lambdaで開発しているので、あとはスケジューリングでもすれば自動起動は簡単ですね。

現状の課題

一応できましたが、いくつかすでにわかっている課題があります。

  1. レコードの一括取得は一度に500件までしかできない。(kintoneの仕様)
  2. レコードの一括登録は一度に100件までしかできない。(kintoneの仕様)
  3. S3へアップロードしたファイルはずっと残ってしまう。(手動で削除しに行かないと後々ゴミになる)
  4. リストアの仕組みがない

この辺を解消するような実装はまた後ほど。

成果物

ここまでの成果物は以下になります。

https://github.com/kojiisd/aws-kintone-backup/tree/v1.0

まとめ

よくあるkintoneアプリケーションのバックアップの一部を自動化することができました。とはいえAPIとしてはプロセス管理やアプリケーションの一般的な設定まで取得するものがあるので、この辺を盛り込むと、どんどんとリッチなバックアップ処理になりそうです。その辺りはまた次にでも。

続きを読む

AWS上にHackMDを構築する

https://github.com/hackmdio/docker-hackmd
GitHub
hackmdio/docker-hackmd
docker-hackmd – docker hackmd image

これをしたい

そのためにはdockerの他にdocker-composeも必要なので (edited)

https://docs.docker.com/compose/install/
↑でdocker-composeをインストールする
Docker Documentation
Install Docker Compose
You can run Compose on macOS, Windows, and 64-bit Linux. Prerequisites Docker Compose relies on Docker Engine for any meaningful work, so make sure you have Docker Engine installed either…

すると、

ERROR: Couldn't connect to Docker daemon at http+docker://localunixsocket - is it running?
If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable.

というエラーで怒られた

ので
https://qiita.com/DQNEO/items/da5df074c48b012152ee
を参考に、今操作しているユーザをdockerユーザグループに追加

続きを読む

Rails appをAWSデプロイしようとしたら<top (required)>’: uninitialized constant Devise (NameError)

はじめに

Railsでアプリケーションの簡単な骨組みだけを作り、AWSでデプロイしようとしたらunicornがうまく走りませんでした。

ps aux | grep unicorn

を叩いて見てもウンともすんとも言わず・・・

気になったので

less log/unicorn.stderr.log

と入力してみたところ下記のエラーが出てきました。

〜〜/config/initializers/devise.rb:5:in `<top (required)>': uninitialized constant Devise (NameError)

ここまでに試したこと

bundle install
bundle update
rails g devise:install

その他
/initializer/devise.rb内のconfig.secret_keyの使用

試してみましたがエラーの改善には繋がりませんでした。

試したこと

/config/application.rb内に

require 'devise'

を記述。エラーがなくなりました。

参考にしたサイト

【Ruby】デプロイ時にDeviseでエラーが発生してしまいます。
https://teratail.com/questions/15041

devise.rb:3: uninitialized constant Devise (NameError)
https://github.com/plataformatec/devise/issues/1605

最後に

自分なりに調べ現象の改善に繋げることができましたが原因がわからないため
「とりあえず改善した方法」の一つだと思われます。
ご参考までに
ruby 2.3.1
Rails 5.0.6
nginx 1.12.1

続きを読む

~/.aws/(config|credentials) の設定から assume roleするラッパーをgolangで実装して、goreleaserでリリースしてみた

最近のgolangのCI周りを勉強する目的で、fujiwaraさんのaswrap – ~/.aws/(config|credentials) で定義した AssumeRole 定義から一時キーを取得してコマンドを起動してくれる wrapperをgolangで再実装してみた。

-> https://github.com/masahide/assumer

まだMFA対応のtodoが残ってたり本家より劣化しているところはありますが、一時キーのキャッシュ保存に対応させたり、rpm,deb,brewのパッケージを作成したので導入が簡単なところぐらいが少ない取り柄

今回やりたかったこと/やったこと

  • goreleaserを使ってrpm,deb,homebrewのパッケージのリリースを自動化
  • codecov.ioでカバレッジの可視化
  • gometalinterで行単位でのignore設定

goreleaser

golang製のソフトウェアのリリース処理を全部引き受けてくれてる便利なツールです。具体的には・・

  • goのクロスコンパイル
  • バイナリのtar.gzアーカイブやrpm,debパッケージ、dockerイメージの作成
  • github.comのGithub Releasesへの添付
  • dockerhubへの登録
  • homebrewのFormula作成
    などかなり幅広く対応しています。

使い方に関しては、 goreleaserを使ってGoで書いたツールのバイナリをGithub Releasesで配布する
を参考にしつつ、goreleaser自身の.travis.yml.goreleaser.ymlがとても参考になるのでこの辺りを真似ながらで基本的に問題ないかと。

codecov.ioでカバレッジの可視化

以前、 golangの静的解析,カバレッジ解析,バイナリリリースをCircleCIで簡単に整えるで使ったcoverallsより導入が簡単だった。
事前にcodecov.ioでトークンを取得して、travisのenvにCODECOV_TOKENとして設定しておいて、あとは、基本的にはこちらもgoreleaserの.travis.ymlを参考にしましたが

.travis.yml
after_success:
  - bash <(curl -s https://codecov.io/bash)

これだけで良いみたいですね。

gometalinterで行単位でのignore設定

gometalinterで様々な静的解析が走るけどその解析ツール毎にignoreを設定するのは大変だなぁと思ってたんですが・・・

https://github.com/masahide/assumer/blob/master/cmd/assumer/main.go#L170

defer cf.Close() // nolint errcheck

のように行単位で// nolint <解析ツール名> でチェックを除外できるようです。
comment-directives に記載されてます。

続きを読む