カテゴリー: tech

  • Linuxでのswap解放

    Linuxでのswap解放

    はじめに

    気がついたらswapを喰っていることがある

    # top
    top - 10:39:58 up 26 days, 16:25,  1 user,  load average: 0.80, 0.31, 0.20
    Tasks: 132 total,   2 running, 130 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  0.0 us,  0.7 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem :  1883152 total,    83772 free,  1363060 used,   436320 buff/cache
    KiB Swap:  1048572 total,   957948 free,    90624 used.   315320 avail Mem 

    この場合は90624 used.

    memoryに抱えきれなかった領域がストレージにdumpされてしまったようだ。ストレージがSSDだったとしても遅いのだが、これがHDDだったりすると阿鼻叫喚だ。

    まず先にやること

    一時的にswapをオフにして、再度オンにする。

    swapoff -a && swapon -a

    ただし、swap outしている領域よりもmemoryが十分に空きがある必要がある。

    他にもアプローチはあることはあるが、

    これで解放できなかったらOS再起動を考えた方が手っ取り早い。

     

  • Failed to Connect to MySQL at localhost: 3306 through SSH tunnel

    Failed to Connect to MySQL at localhost: 3306 through SSH tunnel

    はじめに

    MySQL Workbenchに備わっている sshトンネリング機能を使い、手元のPC/MacからリモートのサーバのDBに繋ぐ方法を紹介。

    やりたいこと

    手元の環境から、MySQL Workbenchがserverにつなぎに行き、そのサーバ内のMySQLに接続させたい。

    workbenchの設定

    Connection Methodを “` Stadard TCP/IP over SSH “` を選択。諸々入力する。

    問題発生

    つながらない

    原因と対処

    mysql内に作成したユーザの接続元を
    127.0.0.1ではなく、localhostとして登録していた。 意味的には同じように思えるが、mysqlの場合はこの辺厳密に区別されるらしい。

    対処

    接続元を127.0.0.1にしてユーザを再作成

    GRANT USAGE ON *.* TO 'tsukada'@'127.0.0.1' IDENTIFIED BY 'password';
    GRANT select ON `database`.* TO 'tsukada'@'127.0.0.1' ;
    
    MariaDB [(none)]> select user,host from mysql.user;
    +----------------+-----------+
    | user           | host      |
    +----------------+-----------+
    | tsukada | 127.0.0.1 |
    +----------------+-----------+
    14 rows in set (0.00 sec)
    
    MariaDB [(none)]> 

    問題なく接続できるようになった

    備考

    リモート接続の際、この本の第三章が非常に良くできている。

    第3章 一歩進んだOpenSSHの使い方
     3-1 TCPポートフォワード
     3-2 プロキシと多段SSH
     3-3 SSHのセッションをコントロールする

    第三章だけでも読む価値はある。とてもおすすめ。

  • CentOS 7/Amazon Linux 2 でtimezoneを変更する

    CentOS 7/Amazon Linux 2 でtimezoneを変更する

    はじめに

    稀にサーバの現在時間を確認しようとした際、想定していた時間と大きくズレていて、見てみるとJST(日本時間)ではなく、UTC(協定世界時)になってある事がある。

    # date
    Wed Oct 17 02:03:17 UTC 2018

    一度設定したらほとんど変更しないタイムゾーン。
    デフォルトでUTCになっていることもあり、JSTに変更したい事が多々ある。

    しかし、変更したい時はだいたい手順を忘れているのでメモを記す。

    手順

    現在のタイムゾーンを確認

    # timedatectl
          Local time: Wed 2018-10-17 02:05:01 UTC
      Universal time: Wed 2018-10-17 02:05:01 UTC
            RTC time: Wed 2018-10-17 02:04:41
           Time zone: n/a (UTC, +0000)
         NTP enabled: yes
    NTP synchronized: no
     RTC in local TZ: no
          DST active: n/a

     

    日本時間に変更する

    # timedatectl set-timezone Asia/Tokyo

    再度タイムゾーンを確認

    # timedatectl
          Local time: Wed 2018-10-17 11:05:17 JST
      Universal time: Wed 2018-10-17 02:05:17 UTC
            RTC time: Wed 2018-10-17 02:04:57
           Time zone: Asia/Tokyo (JST, +0900)
         NTP enabled: yes
    NTP synchronized: no
     RTC in local TZ: no
          DST active: n/a

    Local timeのところがUTCからJSTに変わった。

    この状態でtimeコマンドで現在時間を確認すると,

    # date
    Wed Oct 17 11:05:31 JST 2018

    JSTになり期待通りの結果になる

    もちろん、ログインしなおしてもこの状態は引き継がれる。

    注意事項

    本作業を行うとcronが正常に稼働しない。cronを利用している場合は再起動する必要がある

    systemctl restart crond

     

     

  • GitLabでCLI経由でmerge requestを送る

    GitLabでCLI経由でmerge requestを送る

    はじめに

    GitLabでコマンドベースでmerge requestを作成する。
    postでAPIを叩いていろいろ設定すればそれでも可能だけど、python-gitlabというpython製のツールがとても便利だったので紹介。

    使い方

    pipでpython-gitlabをインストール

    pip install --upgrade python-gitlab

    vi ~/.python-gitlab.cfg

    [global]
    default = somewhere
    ssl_verify = true
    timeout = 5
    
    [somewhere]
    url = https://gitlab.com
    private_token = xXxxxxxxxxxxxxxxxxx
    api_version = 4

    ここで必要になるprivate_tokenはGitLabのユーザ画面から作成することが可能

     

    mergeするスクリプトを作成

    import os
    import gitlab
    
    hostname = '%s' % os.uname()[1]
    
    # gitlabへのURLを入れる
    gl = gitlab.Gitlab('https://gitlab.com/', private_token='xxxxxxxxxxx')
    gl.auth()
    
    # プロジェクト番号をgitlabを調べる
    project = gl.projects.get(123, lazy=True)
    
    mr = project.mergerequests.create({'source_branch': (hostname),
                                       'target_branch': 'master',
                                       'title': (hostname) + ' user list'
                                       })
    
    mrs = project.mergerequests.list(state='opened', order_by='updated_at')[0]
    
    print(mrs.attributes['web_url'])

    実行

    $python merge.py 
    https://gitlab.com/infra/redash-user/merge_requests/30

    作られたmerge requestのページへのリンクが表示される。

    チャットやメールでこのリンクをreviewerに知らせれば、フローも簡略化できる。

    詳しい使い方はこちら

    https://python-gitlab.readthedocs.io/en/stable/index.html

     

  • the input device is not a TTY

    the input device is not a TTY

    はじめに

    cronでdockerコンテナ内のシェルを動かし、結果をリダイレクトしようとした際、

    “` the input device is not a TTY “`

    とエラーが出て、期待通りに動かなかった。

    原因

    /usr/bin/docker exec -it redash_server_1 ./manage.py users list > /tmp/hoge

    cronで動かすのに
    “` docker exec -it “`

    -it のtが邪魔していた。

     

    dockerのコンテナ内に入るとき、もしくはコンテナ内のシェルを動かすとき、docker exec -itがもはや決まり文句のように打っていたが、

    改めてオプションを見直して見ると、-t はTTYデバイスに割り当てるオプションらしい。

     

    https://docs.docker.com/engine/reference/commandline/exec/#usage

    --tty , -t        Allocate a pseudo-TTY

    これがcronで実行するときには不要であり、これがあることによりエラーになる。

    対応策

    tオプションを削る

    /usr/bin/docker exec -i redash_server_1 ./manage.py users list > /tmp/hoge

    これで問題なくcronで実行される

  • RDSのパラメータグループをCLIで取得する

    RDSのパラメータグループをCLIで取得する

    はじめに

    GUIのこの部分のパラメータ

    RDSのパラメータグループをGUIで管理するのは何かとは大変。CLIで取得する

    コマンド

    aws rds --profile=stg describe-db-parameters --db-parameter-group-name default.aurora-mysql5.7

    staging環境や、本番環境など複数の環境を管理している場合は、
    credentialを登録すると、環境を簡単に切り替えられるので便利

    cat ~/.aws/credentials 
    [stg]
    aws_access_key_id = xxxxxxx
    aws_secret_access_key = yyyyyyy
    region=ap-northeast-1
    output=json
    [prd]
    aws_access_key_id = xxxxxxxx
    aws_secret_access_key = yyyyyyy
    region=ap-northeast-1
    output=json

    結果

    $ aws rds --profile=stg describe-db-parameters --db-parameter-group-name default.aurora-mysql5.7
    {
        "Parameters": [
            {
                "ParameterName": "allow-suspicious-udfs",
                "Description": "Controls whether user-defined functions that have only an xxx symbol for the main function can be loaded",
                "Source": "engine-default",
                "ApplyType": "static",
                "DataType": "boolean",
                "AllowedValues": "0,1",
                "IsModifiable": false,
                "ApplyMethod": "pending-reboot"
            },
            {
                "ParameterName": "aurora_lab_mode",
                "ParameterValue": "0",
                "Description": "Enables new features in the Aurora engine.",
                "Source": "engine-default",
                "ApplyType": "static",
                "DataType": "boolean",
                "AllowedValues": "0,1",
                "IsModifiable": true,
                "ApplyMethod": "pending-reboot"
            },

     

     

  • rbenvのインストール

    rbenvのインストール

    はじめに

    rubyを自由にversion切り替えられるrbenvはとても便利。

    しかし、インストールは少しめんどくさい。

    よく使う手順なのでとりあえず晒す

    手順

    以下、コピペでOK。

    インストールしたいversionは適宜変更すること

    yum -y install openssl-devel readline-devel zlib-devel libcurl-devel git
    cd /usr/local
    git clone https://github.com/sstephenson/rbenv.git rbenv
    mkdir rbenv/shims rbenv/versions rbenv/plugins
    groupadd rbenv
    chgrp -R rbenv rbenv
    chmod -R g+rwxXs rbenv
    cd /usr/local/rbenv/plugins
    git clone https://github.com/sstephenson/ruby-build.git ruby-build
    chgrp -R rbenv ruby-build
    chmod -R g+rwxs ruby-build
    git clone https://github.com/sstephenson/rbenv-default-gems.git rbenv-default-gems
    chgrp -R rbenv rbenv-default-gems
    chmod -R g+rwxs rbenv-default-gems
    
    cat << EOF > /etc/profile.d/rbenv.sh
    export RBENV_ROOT="/usr/local/rbenv" 
    export PATH="\$RBENV_ROOT/bin:\$PATH" 
    eval "\$(rbenv init -)" 
    EOF
    
    cat /etc/profile.d/rbenv.sh
    
    cat << EOF > /usr/local/rbenv/default-gems
    bundler
    rbenv-rehash
    EOF
    
    cat /usr/local/rbenv/default-gems
    source /etc/profile.d/rbenv.sh
    rbenv install -l
    
    yum install gcc bzip2
    rbenv install 2.2.5
    rbenv global 2.2.5
    ruby -v
    
    yum install rubygems -y

    Good ruby life!

  • redashでALL Queriesを選択すると “Loading…” のままで変わらない

    redashでALL Queriesを選択すると “Loading…” のままで変わらない

    問題発生

    QueriesがLoadingのままで、Query一覧が表示されない

    redash_serverコンテナには以下のログが吐かれていた

    [2018-10-10 12:48:45,419][PID:14][ERROR][redash] Exception on /api/queries [GET]
    Traceback (most recent call last):
      File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1639, in full_dispatch_request
        rv = self.dispatch_request()
      File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1625, in dispatch_request
        return self.view_functions[rule.endpoint](**req.view_args)
      File "/usr/local/lib/python2.7/dist-packages/flask_restful/__init__.py", line 477, in wrapper
        resp = resource(*args, **kwargs)
      File "/usr/local/lib/python2.7/dist-packages/flask_login/utils.py", line 228, in decorated_view
        return func(*args, **kwargs)
      File "/usr/local/lib/python2.7/dist-packages/flask/views.py", line 84, in view
        return self.dispatch_request(*args, **kwargs)
      File "/app/redash/handlers/base.py", line 31, in dispatch_request
        return super(BaseResource, self).dispatch_request(*args, **kwargs)
      File "/usr/local/lib/python2.7/dist-packages/flask_restful/__init__.py", line 587, in dispatch_request
        resp = meth(*args, **kwargs)
      File "/app/redash/permissions.py", line 48, in decorated
        return fn(*args, **kwargs)
      File "/app/redash/handlers/queries.py", line 197, in get
        with_last_modified_by=False
      File "/app/redash/handlers/base.py", line 106, in paginate
        items = serializer(results.items, **kwargs).serialize()
      File "/app/redash/serializers.py", line 75, in serialize
        result = [serialize_query(query, **self.options) for query in self.object_or_list]
      File "/app/redash/serializers.py", line 105, in serialize_query
        d['user'] = query.user.to_dict()
    AttributeError: 'NoneType' object has no attribute 'to_dict'

    解決へのアプローチ

    とりあえずググる。前例が見つからない。

    twitterで騒ぐ。知ってる人いるかも。

    すぐに見つからない。

    redashのフォーラムに聞いた。

    https://discuss.redash.io/t/when-open-queries-all-queries-always-loading/2449

    redashの生みの親、arikfr がコメントをくれた

    https://discuss.redash.io/t/when-open-queries-all-queries-always-loading/2449/2?u=gitsumito

    あ!確かに消しました。

    そういえばやったこと

    この画面にたどり着く前、redashユーザーの作成を行なった。

    docker exec -it redash_server_1 ./manage.py users create taro@sumito.jp taro

    manage.pyを使い、ユーザーの追加した。

    ちなみにこのmanage.pyを使い、ユーザの追加・削除することは随分前のversionから利用可能で、このコマンドを用いた管理方法は @kakakakakku 氏のブログが非常にわかりやすい 

    ただ、redash version 5.0でredashユーザーの作成を行うと(昔のバージョンもかも)、既に登録されているユーザでも新しく登録できてしまう。

    つまりデータベースに二重に登録されてしまう状態だった。

    この状態で作成したユーザでloginしようとすると、Internal Server Errorになりログインできなくなる。

    仕方なくユーザーを削除することにした

    docker exec -it redash_server_1 ./manage.py users delete taro@sumito.jp

    Successfully。削除できた。

    再度ユーザの作成を行なうと、無事作成したユーザでredashにログインできるようになった。

    めでたし、めでたし。と思ったが、今回の問題

    redashでALL Queriesを選択すると “Loading…” のままで変わらない

    という問題に繋がったようだ。

    解決方法

    postgresのコンテナにログインし、userid周りを調整

    docker exec -it redash_postgres_1 /bin/bash
    psql -U postgres postgres

    redashのユーザ情報が格納されているusersテーブルでidを確認する

    postgres=# select * from users order by id desc;
    updated_at | created_at | id | org_id | name | email | password_hash | groups | api_key | profile_image_url | disabled_at 
    -------------------------------+-------------------------------+----+--------+--------------------+-----------------------------------------+--------------------------------------------------------------------------------------------------------------------------+-----------+------------------------------------------+-------------------+-------------------------------
    (skip)
    2018-08-30 06:48:30.812508+00 | 2018-08-30 06:40:15.029328+00 | 51 | 1 | *** | gomes@sumito.jp | *** | {2,5} | *** | | 
    2018-10-09 08:18:34.331088+00 | 2018-10-09 08:17:20.97545+00 | 55 | 1 | taro | taro@sumito.jp | *** | {2,5} | *** | | 
    2018-10-09 08:18:37.220691+00 | 2018-10-09 08:18:00.078037+00 | 56 | 1 | jiro | jiro@sumito.jp | *** | {2,5} | *** | 

    id 52~54 が欠番していることがわかる。

    これが自分が削除したユーザのID。

    まずはid 52~56のeventテーブルから全ての履歴を削除した

    SELECT * FROM events WHERE user_id = 52;
    DELETE FROM events WHERE user_id = 52;
    
    SELECT * FROM events WHERE user_id = 53;
    DELETE FROM events WHERE user_id = 53;
    
    SELECT * FROM events WHERE user_id = 54;
    DELETE FROM events WHERE user_id = 54;
    
    SELECT * FROM events WHERE user_id = 55;
    DELETE FROM events WHERE user_id = 55;
    
    SELECT * FROM events WHERE user_id = 56;
    DELETE FROM events WHERE user_id = 56;

    これでイベントが全て削除された。

    usersテーブルのid 55,56 を 52,53 に変更した

    update users set id = 52 where email = 'taro@sumito.jp';
    update users set id = 53 where email = 'jiro@sumito.jp';

    その後、user idのインクリメント部分を管理しているusers_id_seq

    を56 から 53に変更した。

    ALTER SEQUENCE users_id_seq RESTART WITH 53;

    対応はこれだけ、

    無事問題が解決した。

    最後に

    CLIを見直すことを示唆してくれた。

    今後のversion upが楽しみ。

  • ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2 “No such file or directory”)

    ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2 “No such file or directory”)

    はじめに

    以下のようなエラーが発生する事がある

    ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2 "No such file or directory")

     

    原因

    mysqlが立ち上がっていない事が多い。

    CentOS7の場合は起動する

    systemctl start mysql

     

  • DQLで手の届きにくいところをredashでなんとかする

    DQLで手の届きにくいところをredashでなんとかする

    はじめに

    DynamoDBを操作するとき、DQLの操作が難しかったり、GroupByができなかったり。SQLでできないところができなかったりすることが多い。redashを使えばそれもなんとかなったりします。

    Query Resultsを活用

    redashにはQeury Resultsという機能があります(2018/10現在、ベータ版)。これは取得したクエリに対し、SQLを用いてデータを結合させたり、編集することができる機能です。

    一度DQLの結果をredashのQuery Resultsを経由させることで細かいところに手が届くようになります。

    Query Resultを指定し、redashで以下のようなクエリを書きます

    select *, sum(price)
    from query_123
    group by userID

    もちろんDQLのみならず、他の言語も似たようにQuery Resultをかえすことで編集可能です。