カテゴリー: tech

  • docker v7 install

    docker v7 install

    はじめに

    公式リポジトリをclonesに、従来のコマンドでredash v7をインストール

    $ docker-compose run --rm server create_db
    
    $ docker-compose up -d

    を試みたところ以下のようなエラーが発生した。

    Browserslist: caniuse-lite is outdated. Please run next command `npm update caniuse-lite browserslist`
    Killed
    npm ERR! code ELIFECYCLE
    npm ERR! errno 137
    npm ERR! redash-client@8.0.0-beta build: `npm run clean && NODE_ENV=production node --max-old-space-size=4096 node_modules/.bin/webpack`
    npm ERR! Exit status 137
    npm ERR! 
    npm ERR! Failed at the redash-client@8.0.0-beta build script.
    npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
    
    npm ERR! A complete log of this run can be found in:
    npm ERR!     /root/.npm/_logs/2019-09-03T05_01_25_105Z-debug.log
    ERROR: Service 'server' failed to build: The command '/bin/sh -c npm run build' returned a non-zero code: 137

    node.js系のエラー?

    docker-compose.ymlを覗いてみると、Dockerfileからビルドする作りになっている。
    コンテナ内部でうまくインストールできなかったのだろうか。

    対処

    インストールで時間を使いたくないのでDocker hubから出来合いのDocker imageをpullして動かすことにした。

    作成したdocker-compose.ymlはこちら。

    https://github.com/GitSumito/redash-v7

    使い方は簡単。

    git clone https://github.com/GitSumito/redash-v7.git
    cd redash-v7
    docker-compose run --rm server create_db
    docker-compose up -d

    これでとりあえず起動することができる。

    http://localhost/setup

    参考情報

    docker-compose.yml を作成する際、非常にお世話になった。カックさんのhandson資料。

    https://github.com/kakakakakku/redash-hands-on

     

     

  • ERROR: Service ‘server’ failed to build: Error parsing reference: “node:10 as frontend-builder” is not a valid repository/tag: invalid reference format

    ERROR: Service ‘server’ failed to build: Error parsing reference: “node:10 as frontend-builder” is not a valid repository/tag: invalid reference format

    はじめに

    git cloneしたリポジトリで “` docker build “` を行ったところ、“` invalid reference format “`というエラーが発生したので、原因と対策について記載する。

    エラー内容

    docker build .
    Sending build context to Docker daemon 7.027 MB
    Step 1/18 : FROM node:10 as frontend-builder
    Error parsing reference: "node:10 as frontend-builder" is not a valid repository/tag: invalid reference format

    原因

    Dockerにmulti stage buildという事ができるようになった事をきっかけに、Dockerfileの書き方が数年前に変わった。

    この記事(https://qiita.com/minamijoyo/items/711704e85b45ff5d6405)にわかりやすく解説してある。

    multi stage buildの名前の通り、docker buildを複数のビルドに分割して実行できる。

    手元のdockerのversionを確認すると、確かに古かった。

    Client:
     Version:         1.13.1
     API version:     1.26
     Package version: docker-1.13.1-102.git7f2769b.el7.centos.x86_64
     Go version:      go1.10.3
     Git commit:      7f2769b/1.13.1
     Built:           Mon Aug  5 15:09:42 2019
     OS/Arch:         linux/amd64
    
    Server:
     Version:         1.13.1
     API version:     1.26 (minimum version 1.12)
     Package version: docker-1.13.1-102.git7f2769b.el7.centos.x86_64
     Go version:      go1.10.3
     Git commit:      7f2769b/1.13.1
     Built:           Mon Aug  5 15:09:42 2019
     OS/Arch:         linux/amd64
     Experimental:    false

    対処

    dockerをremoveし、最新のdocker(docker-ce)をインストールした。

    # rpm -qa | grep docker
    docker-common-1.13.1-102.git7f2769b.el7.centos.x86_64
    docker-client-1.13.1-102.git7f2769b.el7.centos.x86_64
    docker-1.13.1-102.git7f2769b.el7.centos.x86_64

    削除

    rpm -e docker
    rpm -e docker-client
    rpm -e docker-common

    その後、インストール。
    インストール手順は以下公式ドキュメントを参照。

    https://weblabo.oscasierra.net/docker-ce-install-centos7/

     

     

  • Cloud Natural Language API を試した

    Cloud Natural Language API を試した

    はじめに

    Googleがトレーニング済みモデルとして提供している自然言語処理(Natural Language Processing)を使うことで、文字を元に感情分析、エンティティ分析、エンティティ感情分析、コンテンツ分類、構文分析などの自然言語理解の機能がAPI経由で利用できるとのこと。

    Cloud Natural Language APIで、どのような結果を得る事ができるか試してみた。

    どのような事ができるのか

    公式ドキュメントでは以下の通り記載されている

    https://cloud.google.com/sdk/gcloud/reference/ml/language/

    analyze-entitiesUse Google Cloud Natural Language API to identify entities in text.

    analyze-entity-sentimentUse Google Cloud Natural Language API to identify entity-level sentiment.

    analyze-sentimentUse Google Cloud Natural Language API to identify sentiments in a text.

    analyze-syntaxUse Google Cloud Natural Language API to identify linguistic information.

    classify-textClassifies input document into categories.

    上から

    • エンティティ分析
    • エンティティ感情分析
    • 感情分析
    • 構文解析
    • コンテンツ分類

    だ。ひとつひとつ試していったので、実行コマンドと結果とともに解説していく。

    解析対象

    著作権フリーのドキュメントを解析対象とした。

    learningenglish.voanews.comというサイトは著作権フリーでテキスト、MP3を公開しているとのことだったので、今回はそれをコンテンツを利用することにした。

    その中でも「我々のコンテンツは著作権フリーですよ」と記載されているページを解析することにした。

    https://learningenglish.voanews.com/p/6861.html

    https://learningenglish.voanews.com/p/6861.html

    Requesting usage of VOA Learning English content

    Learning English texts, MP3s and videos are in the public domain. You are allowed to reprint them for educational and commercial purposes, with credit to learningenglish.voanews.com. VOA photos are also in the public domain. However, photos and video images from news agencies such as AP and Reuters are copyrighted, so you are not allowed to republish them.

    If you are requesting one-time use of VOA Learning English content, please fill out the information in this form and we will respond to you as soon as possible. For repeat use, please see the Content Usage FAQs on the page.

    High-resolution audio and video files can be downloaded for free through USAGM Direct an online service providing original multimedia content from Voice of America for publication across all platforms: online, mobile, print and broadcast. Access to USAGM Direct requires user registration. If you have any questions about our policies, or to let us know that you plan to use our materials, write to learningenglish@voanews.com.

    各種コマンドを実施した後、リダイレクトとしてテキストに出力させ、結果が膨大なので、上位100桁のみ表示させる。

    なお、Natural Language APIの基本について書かれているドキュメントはこちら。

    https://cloud.google.com/natural-language/docs/basics?hl=ja

    エンティティ分析

    テキストデータからエンティティ(人、組織、場所、イベント、商品、メディアなど)を特定できるようだ。

    実施コマンド

    gcloud ml language analyze-entities --content-file=/tmp/voa.original > /tmp/voa.analyze-entities

    結果

    # head -n100 /tmp/voa.analyze-entities
    {
      "entities": [
        {
          "mentions": [
            {
              "text": {
                "beginOffset": 90,
                "content": "content"
              },
              "type": "COMMON"
            },
            {
              "text": {
                "beginOffset": 518,
                "content": "content"
              },
              "type": "COMMON"
            }
          ],
          "metadata": {},
          "name": "content",
          "salience": 0.1703016,
          "type": "OTHER"
        },
        {
          "mentions": [
            {
              "text": {
                "beginOffset": 60,
                "content": "usage"
              },
              "type": "COMMON"
            }
          ],
          "metadata": {},
          "name": "usage",
          "salience": 0.077866085,
          "type": "OTHER"
        },
        {
          "mentions": [
            {
              "text": {
                "beginOffset": 132,
                "content": "videos"
              },
              "type": "COMMON"
            }
          ],
          "metadata": {},
          "name": "videos",
          "salience": 0.07223342,
          "type": "WORK_OF_ART"
        },
        {
          "mentions": [
            {
              "text": {
                "beginOffset": 0,
                "content": "https://learningenglish.voanews.com/p/6861.html"
              },
              "type": "PROPER"
            },
            {
              "text": {
                "beginOffset": 253,
                "content": "learningenglish.voanews.com"
              },
              "type": "PROPER"
            },
            {
              "text": {
                "beginOffset": 282,
                "content": "VOA"
              },
              "type": "PROPER"
            },
            {
              "text": {
                "beginOffset": 831,
                "content": "Voice of America"
              },
              "type": "PROPER"
            },
            {
              "text": {
                "beginOffset": 1083,
                "content": "learningenglish@voanews.com"
              },
              "type": "PROPER"
            }
          ],
          "metadata": {
            "mid": "/m/0q0r9",
            "wikipedia_url": "https://en.wikipedia.org/wiki/Voice_of_America"
          },
          "name": "https://learningenglish.voanews.com/p/6861.html",
          "salience": 0.07165857,
          "type": "OTHER"
        },

    結果の見方は以下の通り。

    name解析対象の文字列

     

    beginOffset: 指定したテキスト内の文の開始位置を表す(0 から始まる)文字オフセットを示します。このオフセットは、リクエストで渡した encodingType を使用して計算される。

     

    salienceドキュメントのテキスト全体に対するこのエンティティの重要性または関連性を示します。情報の取得や要約の際にエンティティを優先するのに役立ちます。スコアが 0.0 に近いほど重要性が低くなり、1.0 に近いほど重要性が高くなる。

     

    typeドキュメントの種類(HTML または PLAIN_TEXT)などが書かれる。

     

    metadatawikipediaにリンクがあればwikipedia_urlに書かれる。midはGoogle Knowledge GraphのMID(Machine-generated Identifier)が格納される

    エンティティ感情分析

    エンティティ分析と感情分析の両方を組み合わせたものであり、テキスト内でエンティティについて表現された感情(ポジティブかネガティブか)の特定ができるようだ

    実施コマンド

    gcloud ml language analyze-entity-sentiment --content-file=/tmp/voa.original > /tmp/voa.analyze-entity-sentiment
    

    結果

    # head -n100 /tmp/voa.analyze-entity-sentiment
    {
      "entities": [
        {
          "mentions": [
            {
              "sentiment": {
                "magnitude": 0.2,
                "score": 0.2
              },
              "text": {
                "beginOffset": 90,
                "content": "content"
              },
              "type": "COMMON"
            },
            {
              "sentiment": {
                "magnitude": 0.1,
                "score": 0.1
              },
              "text": {
                "beginOffset": 518,
                "content": "content"
              },
              "type": "COMMON"
            }
          ],
          "metadata": {},
          "name": "content",
          "salience": 0.1703016,
          "sentiment": {
            "magnitude": 0.3,
            "score": 0.1
          },
          "type": "OTHER"
        },
        {
          "mentions": [
            {
              "sentiment": {
                "magnitude": 0.5,
                "score": 0.5
              },
              "text": {
                "beginOffset": 60,
                "content": "usage"
              },
              "type": "COMMON"
            }
          ],
          "metadata": {},
          "name": "usage",
          "salience": 0.077866085,
          "sentiment": {
            "magnitude": 0.5,
            "score": 0.5
          },
          "type": "OTHER"
        },
        {
          "mentions": [
            {
              "sentiment": {
                "magnitude": 0.4,
                "score": 0.4
              },
              "text": {
                "beginOffset": 132,
                "content": "videos"
              },
              "type": "COMMON"
            }
          ],
          "metadata": {},
          "name": "videos",
          "salience": 0.07223342,
          "sentiment": {
            "magnitude": 0.4,
            "score": 0.4
          },
          "type": "WORK_OF_ART"
        },
        {
          "mentions": [
            {
              "sentiment": {
                "magnitude": 0.0,
                "score": 0.0
              },
              "text": {
                "beginOffset": 0,
                "content": "https://learningenglish.voanews.com/p/6861.html"
              },
              "type": "PROPER"
            },
            {
              "sentiment": {
                "magnitude": 0.1,
                "score": 0.1
              },
    

     

    magnitude: 指定したテキストの全体的な感情の強度(ポジティブとネガティブの両方)が 0.0+inf の値で示されるscore と違って magnitude は正規化されていないため、テキスト内で感情(ポジティブとネガティブの両方)が表現されるたびにテキストの magnitude の値が増加

    と、公式にはあるが、ドキュメントは正直よくわからないが、以下の表は非常にわかりやすかった。

    感情 サンプル値
    明らかにポジティブ* "score": 0.8、"magnitude": 3.0
    明らかにネガティブ* "score": -0.6、"magnitude": 4.0
    ニュートラル "score": 0.1、"magnitude": 0.0
    混合 "score": 0.0、"magnitude": 4.0

     

    感情分析

    指定されたテキストを調べて、そのテキストの背景にある感情的な考え方を分析することができる。

    実施コマンド

    gcloud ml language analyze-sentiment --content-file=/tmp/voa.original > /tmp/voa.analyze-sentiment

    結果

    # head -n100 /tmp/voa.analyze-sentiment
    {
      "documentSentiment": {
        "magnitude": 4.6,
        "score": 0.2
      },
      "language": "en",
      "sentences": [
        {
          "sentiment": {
            "magnitude": 0.0,
            "score": 0.0
          },
          "text": {
            "beginOffset": 0,
            "content": "https://learningenglish.voanews.com/p/6861.html"
          }
        },
        {
          "sentiment": {
            "magnitude": 0.8,
            "score": 0.8
          },
          "text": {
            "beginOffset": 49,
            "content": "Requesting usage of VOA Learning English content"
          }
        },
        {
          "sentiment": {
            "magnitude": 0.8,
            "score": 0.8
          },
          "text": {
            "beginOffset": 99,
            "content": "Learning English texts, MP3s and videos are in the public domain."
          }
        },
        {
          "sentiment": {
            "magnitude": 0.0,
            "score": 0.0
          },
          "text": {
            "beginOffset": 165,
            "content": "You are allowed to reprint them for educational and commercial purposes, with credit to learningenglish.voanews.com."
          }
        },
        {
          "sentiment": {
            "magnitude": 0.1,
            "score": 0.1
          },
          "text": {
            "beginOffset": 282,
            "content": "VOA photos are also in the public domain."
          }
        },
        {
          "sentiment": {
            "magnitude": 0.4,
            "score": -0.4
          },
          "text": {
            "beginOffset": 324,
            "content": "However, photos and video images from news agencies such as AP and Reuters are copyrighted, so you are not allowed to republish them."
          }
        },
        {
          "sentiment": {
            "magnitude": 0.7,
            "score": 0.7
          },
          "text": {
            "beginOffset": 459,
            "content": "If you are requesting one-time use of VOA Learning English content, please fill out the information in this form and we will respond to you as soon as possible."
          }
        },
        {
          "sentiment": {
            "magnitude": 0.2,
            "score": -0.2
          },
          "text": {
            "beginOffset": 620,
            "content": "For repeat use, please see the Content Usage FAQs on the page."
          }
        },
        {
          "sentiment": {
            "magnitude": 0.3,
            "score": 0.3
          },
          "text": {
            "beginOffset": 684,
            "content": "High-resolution audio and video files can be downloaded for free through USAGM Direct an online service providing original multimedia content from Voice of America for publication across all platforms: online, mobile, print and broadcast."
          }
        },
        {
          "sentiment": {
            "magnitude": 0.3,

    各種項目は今までに説明したものがメイン。大きな特徴はcontentが単語ではなく、文(センテンス)になっているということ。センテンス単位でmagnitudeや、scoreが算出されている。

    そのため、文を通して感情を数値として読み取る事ができる。

    コンテンツ分類

    ドキュメントを分析し、ドキュメント内で見つかったテキストに適用されるコンテンツカテゴリのリストを返す事ができる

    実施コマンド

    gcloud ml language classify-text --content-file=/tmp/voa.original > /tmp/voa.classify-text

    結果

    # head -n100 /tmp/voa.classify-text
    {
      "categories": [
        {
          "confidence": 0.81,
          "name": "/Reference/Language Resources/Foreign Language Resources"
        }
      ]
    }

    “リファレンス/言語リソース/外国語リソース”

    外国語コンテンツのリファレンスということが、なんとなくわかる。

    構文解析

    指定されたテキストを一連の文とトークン(通常は単語)に分解して、それらのトークンに関する言語情報を提供する

    実行コマンド

    gcloud ml language analyze-syntax --content-file=/tmp/voa.original > /tmp/voa.analyze-syntax
    

    結果

    # head -n200 /tmp/voa.analyze-syntax
    {
      "language": "en",
      "sentences": [
        {
          "text": {
            "beginOffset": 0,
            "content": "https://learningenglish.voanews.com/p/6861.html"
          }
        },
        {
          "text": {
            "beginOffset": 49,
            "content": "Requesting usage of VOA Learning English content"
          }
        },
        {
          "text": {
            "beginOffset": 99,
            "content": "Learning English texts, MP3s and videos are in the public domain."
          }
        },
        {
          "text": {
            "beginOffset": 165,
            "content": "You are allowed to reprint them for educational and commercial purposes, with credit to learningenglish.voanews.com."
          }
        },
        {
          "text": {
            "beginOffset": 282,
            "content": "VOA photos are also in the public domain."
          }
        },
        {
          "text": {
            "beginOffset": 324,
            "content": "However, photos and video images from news agencies such as AP and Reuters are copyrighted, so you are not allowed to republish them."
          }
        },
        {
          "text": {
            "beginOffset": 459,
            "content": "If you are requesting one-time use of VOA Learning English content, please fill out the information in this form and we will respond to you as soon as possible."
          }
        },
        {
          "text": {
            "beginOffset": 620,
            "content": "For repeat use, please see the Content Usage FAQs on the page."
          }
        },
        {
          "text": {
            "beginOffset": 684,
            "content": "High-resolution audio and video files can be downloaded for free through USAGM Direct an online service providing original multimedia content from Voice of America for publication across all platforms: online, mobile, print and broadcast."
          }
        },
        {
          "text": {
            "beginOffset": 923,
            "content": "Access to USAGM Direct requires user registration."
          }
        },
        {
          "text": {
            "beginOffset": 974,
            "content": "If you have any questions about our policies, or to let us know that you plan to use our materials, write to learningenglish@voanews.com."
          }
        }
      ],
      "tokens": [
        {
          "dependencyEdge": {
            "headTokenIndex": 0,
            "label": "ROOT"
          },
          "lemma": "https://learningenglish.voanews.com/p/6861.html",
          "partOfSpeech": {
            "aspect": "ASPECT_UNKNOWN",
            "case": "CASE_UNKNOWN",
            "form": "FORM_UNKNOWN",
            "gender": "GENDER_UNKNOWN",
            "mood": "MOOD_UNKNOWN",
            "number": "NUMBER_UNKNOWN",
            "person": "PERSON_UNKNOWN",
            "proper": "PROPER_UNKNOWN",
            "reciprocity": "RECIPROCITY_UNKNOWN",
            "tag": "X",
            "tense": "TENSE_UNKNOWN",
            "voice": "VOICE_UNKNOWN"
          },
          "text": {
            "beginOffset": 0,
            "content": "https://learningenglish.voanews.com/p/6861.html"
          }
        },
        {
          "dependencyEdge": {
            "headTokenIndex": 2,
            "label": "AMOD"
          },
          "lemma": "request",
          "partOfSpeech": {
            "aspect": "ASPECT_UNKNOWN",
            "case": "CASE_UNKNOWN",
            "form": "FORM_UNKNOWN",
            "gender": "GENDER_UNKNOWN",
            "mood": "MOOD_UNKNOWN",
            "number": "NUMBER_UNKNOWN",
            "person": "PERSON_UNKNOWN",
            "proper": "PROPER_UNKNOWN",
            "reciprocity": "RECIPROCITY_UNKNOWN",
            "tag": "VERB",
            "tense": "TENSE_UNKNOWN",
            "voice": "VOICE_UNKNOWN"
          },
          "text": {
            "beginOffset": 49,
            "content": "Requesting"
          }
        },
        {
          "dependencyEdge": {
            "headTokenIndex": 2,
            "label": "ROOT"
          },
          "lemma": "usage",
          "partOfSpeech": {
            "aspect": "ASPECT_UNKNOWN",
            "case": "CASE_UNKNOWN",
            "form": "FORM_UNKNOWN",
            "gender": "GENDER_UNKNOWN",
            "mood": "MOOD_UNKNOWN",
            "number": "SINGULAR",
            "person": "PERSON_UNKNOWN",
            "proper": "PROPER_UNKNOWN",
            "reciprocity": "RECIPROCITY_UNKNOWN",
            "tag": "NOUN",
            "tense": "TENSE_UNKNOWN",
            "voice": "VOICE_UNKNOWN"
          },
          "text": {
            "beginOffset": 60,
            "content": "usage"
          }
        },
        {
          "dependencyEdge": {
            "headTokenIndex": 2,
            "label": "PREP"
          },
          "lemma": "of",
          "partOfSpeech": {
            "aspect": "ASPECT_UNKNOWN",
            "case": "CASE_UNKNOWN",
            "form": "FORM_UNKNOWN",
            "gender": "GENDER_UNKNOWN",
            "mood": "MOOD_UNKNOWN",
            "number": "NUMBER_UNKNOWN",
            "person": "PERSON_UNKNOWN",
            "proper": "PROPER_UNKNOWN",
            "reciprocity": "RECIPROCITY_UNKNOWN",
            "tag": "ADP",
            "tense": "TENSE_UNKNOWN",
            "voice": "VOICE_UNKNOWN"
          },
          "text": {
            "beginOffset": 66,
            "content": "of"
          }
        },
        {
          "dependencyEdge": {
            "headTokenIndex": 6,
            "label": "NN"
          },
          "lemma": "VOA",
          "partOfSpeech": {
            "aspect": "ASPECT_UNKNOWN",
            "case": "CASE_UNKNOWN",
            "form": "FORM_UNKNOWN",
            "gender": "GENDER_UNKNOWN",
            "mood": "MOOD_UNKNOWN",
            "number": "SINGULAR",
            "person": "PERSON_UNKNOWN",
            "proper": "PROPER",
            "reciprocity": "RECIPROCITY_UNKNOWN",
            "tag": "NOUN",
            "tense": "TENSE_UNKNOWN",
            "voice": "VOICE_UNKNOWN"
          },
          "text": {
            "beginOffset": 69,
            "content": "VOA"
          }
        },
        {
          "dependencyEdge": {
            "headTokenIndex": 6,
            "label": "NN"

    文とトークンが抽出され、それらの文(sentences)と中盤以降にトークン(tokens)を含むレスポンスが返される。

    tagはNOUN(名詞)、VERB(動詞)、ADJ(形容詞)などがわかる。

    まとめ

    GCPが使えるようになっていれば非常に簡単にCloud Natural Language API を試す事ができ、使い方によっては非常に有益な解析ができそうだ。

  • zsh: no matches found:  zshでscpコマンドで失敗

    zsh: no matches found: zshでscpコマンドで失敗

    はじめに

    zshでscpコマンドで失敗した。

    % scp -r root@tkd002:/tmp/hoge* .
    zsh: no matches found: root@tkd002:/tmp/hoge*

    原因とその対策についてまとめる

    原因

    zshの補完でひっかかってしまうようだ。

    setopt nonomatch

    .zshrcへ一行追加すればよいが、その場限りの場合は上記コマンドを単純に実行するだけでもよい。

    % setopt nonomatch
    % scp -r root@tkd002:/tmp/hoge* .
    hoge.analyze-sentiment       100% 3865   884.6KB/s   00:00    
    % 

     

     

     

     

  • dockerをECSで動かした時のdebug方法について

    dockerをECSで動かした時のdebug方法について

    はじめに

    dockerコンテナを動かしていると、何らかの原因で起動シェルが止まってしまうことがある。今回はその調査方法の一つ、ECS用にAWSからオフィシャルのログ収集ツール ECSログコレクター が提供されているので、今回はそれを紹介。

    インストール方法

    AWS公式サイトにある通り、ツールを取得する

    $ curl -O https://raw.githubusercontent.com/awslabs/ecs-logs-collector/master/ecs-logs-collector.sh

    その後、sudoをつけてシェルを実行する

    $ sudo bash ./ecs-logs-collector.sh

    しばらくすると、諸々ログが取れる

    $ sudo bash ./ecs-logs-collector.sh
    Trying to check if the script is running as root ... ok
    Trying to resolve instance-id ... ok
    Trying to collect system information ... ok
    Trying to check disk space usage ... ok
    Trying to collect common operating system logs ... ok
    Trying to collect kernel logs ... ok
    Trying to get mount points and volume information ... ok
    Trying to check SELinux status ... ok
    Trying to get iptables list ... ok
    Trying to detect installed packages ... ok
    Trying to detect active system services list ... ok
    Trying to gather Docker daemon information ... ok
    Trying to inspect all Docker containers ... ok
    Trying to collect Docker daemon logs ... ok
    Trying to collect Amazon ECS Container Agent logs ... ok
    Trying to collect Amazon ECS Container Agent state and config ... ok
    Trying to collect Amazon ECS Container Agent engine data ... ok
    Trying to archive gathered log information ... ok

    無事完了すると、correctというディレクトリが作られ、ログが集約される。

    $ ls -ltr
    合計 236
    -rw-rw-r-- 1 ec2-user ec2-user  14181  7月 19 14:25 ecs-logs-collector.sh
    drwxr-xr-x 3 root     root       4096  7月 19 14:25 collect
    -rw-r--r-- 1 root     root     219653  7月 19 14:26 collect-i-0051ca9951de8e82a.tgz

    dockerの状態を確認するには、correct、インスタンスid、配下のdockerディレクトリにログとして出力される。

    /collect/i-xxxxxxxxx/docker

    ざっと見てみると、

    [
        {
            "Id": "xxxxxxx",
            "Created": "2019-07-19T12:36:48.665852002Z",
            "Path": "sh",
            "Args": [
                "/root/bin/execute.sh"
            ],
            "State": {
                "Status": "exited",
                "Running": false,
                "Paused": false,
                "Restarting": false,
                "OOMKilled": true,
                "Dead": false,
                "Pid": 0,
                "ExitCode": 137,
                "Error": "",
                "StartedAt": "2019-07-19T12:36:49.47823385Z",
                "FinishedAt": "2019-07-19T13:12:07.097787961Z"
            },

    終了したときの状態がわかる。

    OOMKilledがtrueになっており、このコンテナはメモリを使い果たし、OOMKillerが発動、コンテナがkillされたのではと推測が立つ。

    linuxのimageをbaseに使っていると、当然メモリーを使い切った際にはOOM killerなどは発生する。その際の原因調査をする上では、サーバレスのfargateよりは、まだホストにログインできるECSの方が原因調査はやりやすい。

    それ以外にも非常に細かい状態を確認することができる。

                "DnsOptions": null,
                "DnsSearch": null,
                "ExtraHosts": null,
                "GroupAdd": null,
                "IpcMode": "shareable",
                "Cgroup": "",
                "Links": null,
                "OomScoreAdj": 0,
                "PidMode": "",
                "Privileged": false,
                "PublishAllPorts": false,
                "ReadonlyRootfs": false,
                "SecurityOpt": null,
                "UTSMode": "",
                "UsernsMode": "",
                "ShmSize": 67108864,
                "Runtime": "runc",
                "ConsoleSize": [
                    0,
                    0
                ],
                "Isolation": "",
                "CpuShares": 2,
                "Memory": 2147483648,
                "NanoCpus": 0,
                "CgroupParent": "/ecs/ad627055-dc5b-4903-96ed-be9e0f25cf33",
                "BlkioWeight": 0,
                "BlkioWeightDevice": null,
                "BlkioDeviceReadBps": null,
                "BlkioDeviceWriteBps": null,
                "BlkioDeviceReadIOps": null,
                "BlkioDeviceWriteIOps": null,
                "CpuPeriod": 0,
                "CpuQuota": 0,
                "CpuRealtimePeriod": 0,
                "CpuRealtimeRuntime": 0,
                "CpusetCpus": "",
                "CpusetMems": "",
                "Devices": null,
                "DeviceCgroupRules": null,
                "DiskQuota": 0,
                "KernelMemory": 0,
                "MemoryReservation": 1073741824,
                "MemorySwap": 4294967296,
                "MemorySwappiness": null,
                "OomKillDisable": false,
                "PidsLimit": 0,
                "Ulimits": [
                    {
                        "Name": "cpu",
                        "Hard": 0,
                        "Soft": 0
                    },
                    {
                        "Name": "nofile",
                        "Hard": 4096,
                        "Soft": 1024
                    }
                ],
                "CpuCount": 0,
                "CpuPercent": 0,
                "IOMaximumIOps": 0,
                "IOMaximumBandwidth": 0,
                "MaskedPaths": [
                    "/proc/acpi",
                    "/proc/kcore",
                    "/proc/keys",
                    "/proc/latency_stats",
                    "/proc/timer_list",
                    "/proc/timer_stats",
                    "/proc/sched_debug",
                    "/proc/scsi",
                    "/sys/firmware"
                ],

    詳細はこちら。

    https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-logs-collector.html

    では、今日はこの辺で。

     

     

  • 作業ブランチを別リポジトリのブランチへ引っ越し

    作業ブランチを別リポジトリのブランチへ引っ越し

    はじめに

    アプリケーションを作っていると、当初作ろうとしていたものと、今作っているものが徐々にズレてくることがある。

    その時に考えることの一つが、「リポジトリどうしよう」ってやつだ。

    新しいリポジトリとはいえ、いきなりmasterにpushするのもなんだか忍びない。

    今回はリポジトリのブランチを別のリポジトリのブランチとしてコピーする方法を紹介。

    やりたいこと

    いたって簡単。

    これだ。これをやりたいのだ。

    コマンド

    # 新しいリポジトリをclone
    git clone git@git.sumito.com:hoge/AFTER-REPO.git
    cd AFTER-REPO
    git checkout -b AFTER-BRANCH
    
    # remote登録
    git remote add tmpbranch git@git.sumito.com:hoge/BEFORE-REPO.git
    git pull tmpbranch AFTER-BRANCH --allow-unrelated-histories
    
    # 新BRANCHへpush
    git add .
    git commit -m 'copy'
    git remote rm tmpbranch
    git push origin AFTER-BRANCH

    あとはpushした先で期待通りになっているか確認するだけでよい。

     

  • Error getting valid credentials (AKID ): NoCredentialProviders: no valid providers in chain. Deprecated.

    Error getting valid credentials (AKID ): NoCredentialProviders: no valid providers in chain. Deprecated.

    はじめに

    ECSでコンテナを動かそうとすると、作成されるEC2でdocker logsに

    2019-07-08T12:17:52Z [INFO] Event stream ContainerChange start listening...
    2019-07-08T12:17:52Z [WARN] Error getting valid credentials (AKID ): NoCredentialProviders: no valid providers in chain. Deprecated.
    	For verbose messaging see aws.Config.CredentialsChainVerboseErrors
    2019-07-08T12:17:52Z [INFO] Registering Instance with ECS
    2019-07-08T12:17:52Z [INFO] Remaining mem: 3885
    2019-07-08T12:17:52Z [ERROR] Unable to register as a container instance with ECS: NoCredentialProviders: no valid providers in chain. Deprecated.
    	For verbose messaging see aws.Config.CredentialsChainVerboseErrors
    2019-07-08T12:17:52Z [ERROR] Error registering: NoCredentialProviders: no valid providers in chain. Deprecated.
    	For verbose messaging see aws.Config.CredentialsChainVerboseErrors

    というエラーが記述された。その原因と対策を明記する。

    原因

    ecsを実行するEC2インスタンスのroleに適切な権限がない。

    roleに以下の通り権限を付与する

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ecs:CreateCluster",
                    "ecs:DeregisterContainerInstance",
                    "ecs:DiscoverPollEndpoint",
                    "ecs:Poll",
                    "ecs:RegisterContainerInstance",
                    "ecs:StartTelemetrySession",
                    "ecs:UpdateContainerInstancesState",
                    "ecs:Submit*",
                    "ecr:GetAuthorizationToken",
                    "ecr:BatchCheckLayerAvailability",
                    "ecr:GetDownloadUrlForLayer",
                    "ecr:BatchGetImage",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "*"
            }
        ]
    }

     

    もしEC2へattachするroleを変更したい場合は、ECSの画面からではなく、CloudFormationの画面から変更を行う。

    これは、ECSのサービス作成時、裏でCloudFormationが実行されるため。

    具体的な手順はクラメソさんのBlogが非常にわかりやすい。

    https://dev.classmethod.jp/cloud/aws/ecs-change-instance-type/

    変更点は以下の箇所

     

    有効化するには現在起動しているEC2インスタンスをterminateすること。

    オートスケールの設定がされているので、自動で新しい設定のインスタンスが立ち上がる。

     

     

     

     

     

     

  • go言語で自分のlocalIPを取得する

    go言語で自分のlocalIPを取得する

    はじめに

    dockerコンテナでgoのプログラムを動かしていると、コンテナのIPをどのように取得すればよいか困ったのでその対処を紹介。

    コード

    package main
    
    import (
    	"fmt"
    	"net"
    )
    
    func main() {
    
    	netInterfaceAddresses, _ := net.InterfaceAddrs()
    
    	for _, netInterfaceAddress := range netInterfaceAddresses {
    
    		networkIp, ok := netInterfaceAddress.(*net.IPNet)
    
    		if ok && !networkIp.IP.IsLoopback() && networkIp.IP.To4() != nil {
    
    			ip := networkIp.IP.String()
    
    			fmt.Println("Resolved Host IP: " + ip)
    
    		}
    	}
    }

    解説

    至ってシンプル。 “` net.InterfaceAddrs() “` でIPを取得することが可能だ。

    127.0.0.1 で表現できない時など、テストコードなどで活躍しそう。

  • You must specify a region. You can also configure your region by running “aws configure”.

    You must specify a region. You can also configure your region by running “aws configure”.

    はじめに

    ECSでタスクロールを指定しているのに、ECSで動かしたコンテナ内でawsコマンドを使うと、aws configureをしてくれとエラーが出る際の対処。

    You must specify a region. 
    You can also configure your region by running "aws configure".

    原因

    エラーメッセージの通りregionが指定されていないから。

    コンテナに以下の設定を入れるよう、Dockerfileを修正する。

    [default]
    region=ap-northeast-1
    output=json

     

     

     

  • 【Docker】ストレージ容量不足時の対処法【解決済み】

    【Docker】ストレージ容量不足時の対処法【解決済み】

    はじめに

    Dockerのビルドサーバーでストレージ不足が発生しました。
    不要なファイルを削除する必要があるため、安全に容量を確保する方法を紹介します。
    dockerで/var/lib/docker/overlay2 が肥大化した時の対処になります。

    まず対応すべきこと

    現状把握

    Dockerがディスク容量を圧迫している原因を確認するため、以下のコマンドを使用します。

    docker system df このコマンドで、Dockerに関連するディスク使用状況を確認できます。

    TYPE TOTAL ACTIVE SIZE RECLAIMABLE
    Images 9 1 2.014GB 1.962GB (97%)
    Containers 2 0 0B 0B
    Local Volumes 4 2 824.6MB 781.2MB (94%)
    Build Cache 0 0 0B 0B
    対処

    使用されていないコンテナ、ボリューム、ネットワーク、イメージを削除するには、以下のコマンドを使用します。

    docker system prune

    ただし、使用されていないボリュームとイメージを削除するには、以下のオプションが必要です。
    docker system prune --volumes --all

    volumesの削除

    上記コマンドで、不要なvolumesを削除しました。この操作で、355.4MBの容量を確保できます。ただし、storageの削除には、–volumesオプションを追加する必要があります。

    53d15cd6b78ad0f21788a22e9ce16a7295c4bab97609973
    deleted: sha256:7ae9338aed73a0f33568db53740431038d3a1f779c4dae40d27433984e1cd97c
    deleted: sha256:b1be54c8cadff1e50b87b93559320a1ae57b8d0dd326507148f7ca81d707beed
    deleted: sha256:86d78f10b9718618eaae056f5dfa1edae518949aee4578e4147268e9db2e75f0

    Total reclaimed space: 355.4MB
    ただし、storageの削除には、 --volumes オプションを追加する必要があります。

    imagesの削除

    docker system prune --all

    作業後

    上記の操作を完了した後、Dockerのディスク使用状況を再度確認すると、すべてのカテゴリーで容量が0になります。