docker exec で cd する方法

dockerを使っていて、普段は↓のコマンドでコンテナ内に入って作業してます。

$ docker exec -it {container-name} /bin/bash

最近はコンテナ内でお決まりの作業(特定のディレクトリに移動してコマンド実行など)をしたいときに

$ docker exec -i {container-name} "cd /path/to && ls"

の様な形で実行できると思っていたのですが、実際は違っていて上手くいきませんでした。
↓の様なエラーが出ました。

$ docker exec -i {container-name} "cd /var/log && ls"
oci runtime error: exec failed: container_linux.go:265: starting container process caused "exec: \"cd /var/log && ls\": stat cd /var/log && ls: no such file or directory"

cd する方法

$ docker exec -i {container-name} /bin/bash -c "cd /path/to && ls"

という風に、 /bin/bash -c としてその後に実行したいコマンドを書いてあげると動く。

参考

docker-exec failed: "cd": executable file not found in $PATH - Stack Overflow

ISUCON7予選に参加しました

id:Maco_Tasu に、ISUCONに一緒に出ませんかと誘ってもらえたのでいい機会だしと思い参加しました。

LabALICEというチームで、メンバーはid:Maco_Tasu, id:karia です。

macotasu.hatenablog.jp

karia.hatenablog.jp

全員のスコアと順位を出して頂けて運営の方には感謝です。

isucon.net

最終スコアは 79,590 で、43位でした。

当日私は、画像周りの修正をしたのでそのあたりについて記録を残しておこうと思います。

事前準備

チームで3回集まって過去問を解きました。
解いた過去問は

  • isucon6予選
  • isucon4予選
  • pixiv社の社内向けisucon

です。

過去問を解くことで全体的な流れを掴むことができました。
そこで一番感じたのが、競技中にNginxの設定などを動作確認しながら作成してると時間がもったいないということでした。
NginxやMySQLなど、あらかじめ使うであろう物の設定ファイルはひな形を作っておこうとチームで話あって事前準備をしていました。

当日

最初の役割分担は id:Maco_Tasugithubへのソースコード登録、id:karia がインフラの整備となっていました。
私は、DBテーブルの確認をしてからアプリを触って動作確認をしていました。
今回のお題はチャットアプリで、画像の数が多いためNginxから返せれば速くなるのかなと思いながら触ってました。

一通りアプリを触ったので、ソースコードの確認に入りました。
ソースコードを見ると、pixiv社の社内向けisuconと同様に画像をMySQLに入れている部分が目に付きました。

予選の環境はDBサーバー1台とAPサーバー2台の構成でした。
画像はMySQLにいれるのを止めてローカルに保存してNginxから返す様にするというのはすぐに思いつきました。
問題はどのサーバーで保存するかというところで少し考えました。

  1. APサーバーからDBサーバーのMySQLに画像を保存するのを止める
  2. DBサーバーのローカルに画像を保存する

と考えたときに、DBサーバーのローカルに保存したいならDBサーバーをフロントにして、画像の保存はDBサーバーがやってそれ以外の処理は後ろのAPサーバーに流してあげれば良いんじゃないかと考えてインフラの構成を変更しました。

インフラの変更は id:karia にお願いをして、アプリの改修をしました。
改修内容は下の2つです。

  • 画像の登録/更新があったらMySQLには保存せずにローカルに保存する
  • 初期にDBに登録されている画像をローカルに書き出しておく

この後ベンチを回したりして動作を確認していたのですが、どうもDBサーバーの負荷が高くフロントと兼任させるのは良くないという事がわかってきました。
ここで、構成を変更することにしました。

次に試した方法は AP1台をフロントにして、フロント・AP・DBがそれぞれ1台づつの構成です。

  • フロントサーバーは、追加された画像のローカル保存
  • APは、画像処理以外の実行

に担当を分けてみました。

この構成だとDBに余裕ができたので、スコアを上げることができました。
その後は、GET /message GET /history/:channel_id のクエリを直したりということをしていました。

結果は予選敗退でしたが、気づきがとても多く参加して良かったと思います。
運営の皆様ありがとうございました。
id:Maco_Tasu, id:karia チームを組んでくれてありがとうございました。

学び/勘違いしていたこと

  • DBの接続設定

リクエストごとにコネクションが作られる

def db
  return @db_client if defined?(@db_client)

  @db_client = Mysql2::Client.new(

コネクションの使い回しができる

def db
  return Thread.current[:isuconp_db] if Thread.current[:isuconp_db]
  client = Mysql2::Client.new(
  • MySQLのコネクションがちゃんと閉じられていることを確認するのは大切

javascriptのスプレッド演算子(...)

javascriptで関数を呼び出すところで、引数に ... と書いているソースコードを見かけるがこれが何か調べてみた。

ES2015から追加された、スプレッド演算子というらしい。

参考

「…」←これ、ただの省略記号かと思ってました。(Spread operatorのお話)|もっこりJavaScript|ANALOGIC(アナロジック)

スプレッド演算子 - JavaScript | MDN

TypeScript2からのReactとnon-null assertion

TypeScript2からコンパイルオプションの strictNullChecks で、nullability をチェックできるようになった。
最近になってこのオプションを有効にしたら意外と修正するところが多かったのでメモ。

TypeScript1系の時は↓の様に書いてました。

import * as React from 'react'
import * as ReactDom from 'react-dom'

interface IAProps {
}
interface IAState {
  hoge?: string;
  fuga?: number;
}
class A extends React.Component<IAProps, IAState> {
  constructor(props: IAProps) {
    super(props);

    this.state = {
      hoge: '',
      fuga: 0
    }
  }

  render() {
    return(
      <B
        hoge={this.state.hoge}
        fuga={this.state.fuga}
      />
    );
  }
}

interface IBProps {
  hoge: string;
  fuga: number;
}
interface IBState {
}
class B extends React.Component<IBProps, IBState> {
  constructor(props: IBProps) {
    super(props);

    this.state = {
    }
  }

  render() {
    return(
      <div>
        {this.props.hoge}
        <br />
        {this.props.fuga}
      </div>
    );
  }
}

TypeScriptでstate管理するときは、毎回全部のパラメータを更新したいわけではないので

interface IAState {
  hoge?: string;
  fuga?: number;
}

という感じに? を付けてオプショナルにしていました。

そうすると、stateで管理しているhoge fugaの型が

hoge: string | undefined
fuga: number | undefined

と、それぞれ undefined になる可能性があるということになる。

Component B に値を渡すとき、Component B側では

interface IBProps {
  hoge: string;
  fuga: number;
}

というようにundefinedは許容されないので、

  render() {
    return(
      <B
        hoge={this.state.hoge!}
        fuga={this.state.fuga!}
      />
    );

!を付けて、non-nullであることを明示してあげないといけない。

最終的にソースコードはこうなりました。

import * as React from 'react'
import * as ReactDom from 'react-dom'

interface IAProps {
}
interface IAState {
  hoge?: string;
  fuga?: number;
}
class A extends React.Component<IAProps, IAState> {
  constructor(props: IAProps) {
    super(props);

    this.state = {
      hoge: '',
      fuga: 0
    }
  }

  render() {
    return(
      <B
        hoge={this.state.hoge!}
        fuga={this.state.fuga!}
      />
    );
  }
}

interface IBProps {
  hoge: string;
  fuga: number;
}
interface IBState {
}
class B extends React.Component<IBProps, IBState> {
  constructor(props: IBProps) {
    super(props);

    this.state = {
    }
  }

  render() {
    return(
      <div>
        {this.props.hoge}
        <br />
        {this.props.fuga}
      </div>
    );
  }
}

参考

15K 行のアプリを TypeScript 1.8 から 2.0 に移行してみた - はやくプログラムになりたい

go言語をインストールしてvimで保存時にコードフォーマットを走らせるまでの設定

Macの環境でgo言語をインストールして、vimソースコード保存時に自動でコードフォーマットが走るまでの環境設定です。

普段はIDEを使うので、vimでファイル保存時に go fmt を実行させる設定に手間取ってしまったのでメモしておきます。
vimプラグイン追加方法がわからなかっただけです。

go言語のインストール

$ brew install go

ここまでで、go言語を書いてコンパイルして実行まではできるようになります。

go言語は標準で go fmt でコード整形できるのですが、vimでファイル保存時に go fmt を実行して欲しいのでその設定方法についてです。

vimで go fmt するまでの設定

1. vim-plugをインストールする

$ curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

2. ~/.vimrcプラグインを読み込むようにする

~/.vimrc に下記3行を追加

call plug#begin('~/.vim/plugged')

Plug 'fatih/vim-go'

call plug#end()

3. vim をリロードして :PlugInstall を実行

ここまでの設定で vimでファイル保存時に自動で go fmt が実行されるようになります。

AWS CloudFormationでECSを管理するときにハマったこと

CloudFormationでECSを構築したときにハマったメモです。

CloudFormationのテンプレートを書いて

  • AWS::ECS::Cluster
  • AWS::ECS::Service
  • AWS::ECS::TaskDefinition

あたりの設定をして、構築しました。

動作確認ができたので、AWS::ECS::Service の設定を更新しました。
更新をしてみたところ、更新中のステータスから一向に進みませんでした。

テンプレートを確認すると、↓のようになっていました。
(下のテンプレートは余分な部分は書いてません)

  Service:
    Type: AWS::ECS::Service
    Properties:
      DeploymentConfiguration:
        MaximumPercent: 100
        MinimumHealthyPercent: 50

MaximumPercent: 100 ということで、新しいコンテナを追加できないのに追加しようとして動かない状態でした。 この状態だと、CloudFormationのタイムアウトを設定しないとずっと、更新中のステータスになってしまいます。

管理画面から手動でサービスの更新でタスク数を0にしてあげれば解決できました。

nodeのバージョン管理にnaveを使おうと思ったら上手くいかなかったのでメモ

basherからnaveをインストールしたあと、

$ nave use latest

を実行したところ、nodeのインストールに失敗した。

$ nave cache clear

したら直った

環境

AWS EC2 OS Debian Jessie AMI ami-dbc0bcbc

問題が発生した手順

  1. basherインストール
  2. naveインストール
  3. nodeインストール

basherのインストール

basherのInstallation手順に沿ってインストールした github.com

$ git clone https://github.com/basherpm/basher.git ~/.basher
$ echo 'export PATH="$HOME/.basher/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(basher init -)"' >> ~/.bash_profile
$ bash
$ basher update

naveインストール

naveのInstallation手順に従ってインストールした github.com

$ basher install isaacs/nave

nodeインストール(問題が起きたところ)

最新版のnodeを使おうと思い下記コマンドを実行した

$ nave use latest

コマンド結果

What version of node?
lts, lts/<name>, latest, x.y, or x.y.z >

ここで latest と入力してもnodeのインストールは実行されませんでした。

下記の通りキャッシュをクリアしたらインストールできました。

$ nave cache clear
$ nave use latest