Mac+python3.7でSSL: CERTIFICATE_VERIFY_FAILEDが発生する場合の対応

BeautifulSoup4を使った時に発生したエラー

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1317, in do_open
    encode_chunked=req.has_header('Transfer-encoding'))
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1229, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1275, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1224, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1016, in _send_output
    self.send(msg)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 956, in send
    self.connect()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1392, in connect
    server_hostname=server_hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 412, in wrap_socket
    session=session
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 853, in _create
    self.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 1117, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1051)

During handling of the above exception, another exception occurred:

解決策:

$ /Applications/Python\ 3.7/Install\ Certificates.command

参考:
https://qiita.com/orangain/items/0a641d980019fd7e0c52

最新バージョンのgitをインストールする

最新バージョンはここから確認する

環境はGCPのCentOS7

yum groupinstall 'Development Tools'
yum -y install zlib-devel perl-ExtUtils-MakeMaker

cd /usr/local/src
wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.9.5.tar.gz
tar zxvf git-2.9.5.tar.gz 
cd git-2.9.5
./configure --prefix /usr/local/git-2.9.5
make
make install
git --version
git version 2.9.5

上場したてのベンチャー企業に中途入社して5ヶ月で辞めました

タイトルの通りの退職エントリーになります。
2018年3月1日から株式会社ZUUでお世話になっていましたが、2018年8月末をもって退職する事になり、29日が最終出社でした。

21歳の時からIT業界に身を置いてきましたが、たった5ヶ月という最短記録を更新する状況になり、決断が早すぎたかもしれないと少し感じます。

辞めた経緯を以下に記載しますが、会社が悪いと批判するつもりは無く、事業自体はとても面白い事をやろうとしている会社だと思います。

ただ、私がベンチャー企業に求めていた事と、会社の考えの違いがあまりにも大きく、それについて幾度となく改善の指摘をしても変わる気配が無かった。
それだけの事です。

ベンチャー企業に求めていた事
”一緒に”作り上げていく面白さ

前職は韓国の大手ゲーム会社の子会社で働いており、何故か日本法人の仕事も見るポジションでした。
そこで感じたのは、セクショナリズムがゴリゴリに強く、検討についての議論が一切出来ない。というものでした。
(申請ベースで作業依頼が届き、必要性や用途のヒアリングして構築する。作業レイヤーもOSのチューニングまでとシンプルかつ面白味も無い)

ベンチャーと言う言葉に夢を見ていたと言われればそうかも知れませんが、ZUUの開発部門は正社員、契約社員、業務委託の合計で8名程度の小規模のチームにも拘らず適切な情報共有もない状態で、来週・来月に何をやらなければならないのか?がチーム内で共有されず、不明瞭なまま動いている状態でした。

企画者や中間層の会議で「○○やりたい!」「いいねぇ!」などが話され、そのまま開発に降ってくる。という状況でしょうか。
私がやりたかったのは、その会議の中で一緒に決めていく事でしたが、在籍していた5ヶ月間の間で他部門と会議を行った事は1度もありません。

bigquery事件
一番ビックリしたのは、DMPツールとしては他の製品を使っているにも拘らず、「ドヤりたいからbigquery使いたい!」でした。

bigqueryを使って何を分析するのか?が目的になっていないので、要件なんてありません。
とりあえず、既に一部をDMPツールに送信しているアプリケーションのログをbigqueryにも送り始め、re:dashで可視化させたり集計してスプレットシートに吐いたりとやりましたが、意味があるのか無いのか未だに分かりません。

cockroachDB事件
仕様決め、共有が無いのが1番辛かったです。
百歩譲って、構成や使い方に変動がないケースで共有が無かったり遅れる場合は、まだ理解出来ます。
開発環境が各個人のDockerの為、インフラに頼らなくても開発には支障がないでしょうが、
開発のプルリクエストでチラ見して気づいたcockroachDBの導入についても「インフラとして調査すらしてないよ?」とかもありました。

その時は、さすがに頭に来てしまい、

と、口汚くslackで上司に話を投げましたが、この回答があり非常にガッカリした記憶があります。

他部門との会議は基本的に室長が行なっており、そこで決まる仕様や要件などフィードバックが無い。
なぜ数名しかいない開発チームなのにコミュニケーションロスが生じるのか?
とても理解に苦しみます。

これらのやり方が変わらない限り、ZUUにエンジニアが定着する事は無いと思います。
リファラル採用も募集していましたが、こんな劣悪な体制に知り合いエンジニアを売るような事は出来ません。

開発を外注するにしても、社内で仕様や要件を決められない為、それも難しいでしょう。
(高額なSIerにお願いすれば別ですが)

次は何するの?

またベンチャー企業と呼ばれる環境に身を置きたいと思っているので、次の転職先もZUUと同じ規模の会社になります。

次こそ”一緒に作り上げて行ける”ように、頑張りたいと思います。

grafanaでワールドマップを利用する


grafanaでworld map プラグインを使ってみたので備忘録

マッピングデータは、MaxMaindさんが提供してくれているものを使います。
https://dev.maxmind.com/ja/geolite2/

ElasticSearchを使う方法が一般的みたいですが、ざっくり国別データを集計したいだけなので、MySQLで行きます。
また、アクセスログもInfluxDBではなくMySQLです。

【環境】
python3.4
Mysql 5.7
maxminddb 1.4.1

まずはモジュールインストールと、マッピングデータの取得

pip3 install maxminddb
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz -P /usr/local/src

MySQLにテーブルを作る

CREATE TABLE `geo2` (
  `ip_address` varchar(15) DEFAULT NULL,
  `country_name` varchar(50) DEFAULT NULL,
  UNIQUE KEY `ip_address` (`ip_address`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

pythonスクリプトを作る。
vim /usr/local/bin/insert_get2.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import MySQLdb
import os
import maxminddb
import datetime

DBFILE = '/usr/local/src/GeoLite2-City.mmdb'
geo2db = maxminddb.open_database(DBFILE)

# 直近1時間前のログからデータ集計を行う
todaydetail = datetime.datetime.today()
starttime = (todaydetail-datetime.timedelta(hours=1)).strftime("%Y-%m-%d %H:00")
endtime   = todaydetail.strftime("%Y-%m-%d %H:00")

def geo2(ips):
  val_list = []
  for ip in ips:
    try:
      location = geo2db.get(ip)
      # 国
      country = location["registered_country"]["iso_code"]

      # 経度と緯度も取得出来るけど今回は使わない
      # 緯度
      # latitude = location['location']['latitude']
      # 経度
      # longitude = location['location']['longitude']

      val_list.append([ip,country])
    except:
      pass

  return val_list

def db_select():
  con = MySQLdb.connect(
    host='localhost',
    db='log',
    user='DBユーザー',
    passwd='パスワード',
    charset='utf8'
  )

  cur = con.cursor()
  sql = "select distinct remote_ip from log where time between '{start}' and '{end}' and remote_ip != '::1'".format(start=starttime,end=endtime)

  result = cur.execute(sql)
  ips = []
  for ip in cur:
    ips.append(ip[0])

  cur.close()
  con.close()
  return ips


def db_bulk_insert(rows):
  con = MySQLdb.connect(
    host='localhost',
    db='log',
    user='DBユーザー',
    passwd='パスワード',
    charset='utf8'
  )

  cur = con.cursor()
  sql = "INSERT IGNORE geo2(ip_address,country_name) VALUES(%s, %s)"
  cur.executemany(sql,rows)
  con.commit()
  cur.close()
  con.close()

ips  = db_select()
rows = geo2(ips)
db_bulk_insert(rows)

あとは、/usr/local/bin/insert_get2.pyを1時間毎に実行する。

GCEインスタンスでpostgresqlをフェイルオーバーさせる

GCEでは、単一インスタンスに同一ネットワークのIPアドレスを複数持たせる事ができない。
複数のネットワーク インターフェースの概要と例

つまり、Virtual IPを同一セグメントに持たせた構成は出来ない。

クラスタを組みたかったけど、今回の要件としては

1. Active/Standbyの構成にする
2. Activeのpostgresが止まった場合、Standbyを昇格する
3. フェイルバックは行わない。
4. フェイルオーバー後、App側で検知。
   必要な設定変更後、動的にサービスの再起動を行う。
5. 1分以内にサービスが復旧される。

とシンプルな構成にする。

PostgreSQL

要件1、2には、pg_keeperを使う。
クラスタでは無いのでスプリットブレインの検知などは出来ない。
その為、アプリケーション側に今のActive機の情報を教える必要がある。

スプリットブレイン対策用のDB、Table作成

postgres=#  create database pg_state;
postgres=#  create table failover_log (unixtime int, host varchar(10));

インストール(Actice/Standby共に)

cd /usr/local/src

git clone https://github.com/MasahikoSawada/pg_keeper.git

export PATH=/usr/pgsql-9.6/bin/:$PATH

make USE_PGXS=1

make USE_PGXS=1 install

postgresql.conf書き換え(Actice/Standby共に)

vim postgresql.conf

shared_preload_libraries = 'pg_keeper'
pg_keeper.my_conninfo = 'host=10.0.0.10 port=5432 dbname=postgres'
pg_keeper.partner_conninfo = 'host=10.0.0.11 port=5432 dbname=postgres'
pg_keeper.keepalive_time = 2
pg_keeper.keepalive_count = 3
pg_keeper.after_command = 'sleep 1 ; psql -d pg_state -c "insert into failover_log values(`date +%s`, \'`hostname`\');" -x'

Activeが止まった場合、pg_keeper.keepalive_time秒 × pg_keeper.keepalive_count回 チェックを行い、全てNGの場合にフェイルオーバーを実行し、最後にpg_keeper.after_commandの内容が実行される。
今回は、フェイルオーバー後に[unixtimestamp, hostname]を pg_state.failover_logに入れている。

app側

これはアプリケーションのよるので参考まで。
monitor_master_db.pyというモニタリングスクリプトを作成し、root権限で動かす事にした。
動きとしては、Active/Standby両機のDBのpg_state.failover_logをチェックし、タイムスタンプが若い方をDB接続先として、設定ファイル(yaml)を書き換えデーモンの再起動を行う。

#!/bin/env python3

import os,sys
import yaml
import psycopg2
import codecs
import subprocess

yaml_file = '/PATH/TO/env.yaml'
dbs = ['postgresql://postgres@db01:5432/pg_state'
         ,'postgresql://postgres@db02:5432/pg_state']

def get_item():
    arr = []
    for db in dbs :
        try:
            dbcon = psycopg2.connect(db)
            cur = dbcon.cursor()
            cur.execute('select * from failover_log order by unixtime desc limit 1')
            result = cur.fetchone()
            cur.close()
            dbcon.close()
            arr.append(result)
        except :
            pass
    if len(dbs) == len(arr):    # Active/Standby共にデータ取得成功
        if arr[0][0] > arr[1][0]:
            return arr[0][1]
        else :
            return arr[1][1]

    else :                             # 片系が停止している
        return arr[0][1]


def overwrite(db_name):
    with codecs.open(yaml_file, 'r', 'utf-8') as read :
        env_dict = yaml.load(read)

        if env_dict['db_master'][0]['address'] != '{}:5432'.format(db_name) or env_dict['db_slave'][0]['address'] != '{}:5432'.format(db_name):
            env_dict['db_master'][0]['address'] = '{}:5432'.format(db_name)
            env_dict['db_slave'][0]['address'] = '{}:5432'.format(db_name)

            with codecs.open(yaml_file, 'w', 'utf-8') as write :
                yaml.dump(env_dict, write, encoding='utf8', allow_unicode=True, default_flow_style=False)

            try:
                subprocess.check_call(["systemctl", "restart", "デーモン"])
            except :
                pass

作成したmonitor_master_db.pyをcronで動かす。
cronは普通に書くと1分が最小の実行単位だが、以下のように書くと5秒単位でスクリプトを実行してくれる。

# 5秒間隔
* * * * * for i in `seq 1 12`;do sleep 5; python3 /usr/local/bin/monitor_master_db.py; done

# 10秒間隔の場合
* * * * * for i in `seq 1 6`;do sleep 10; python3 /usr/local/bin/monitor_master_db.py; done

この状態で、Active側のDBを落として、フェイルオーバーされApp側の接続先も変更される事を確認する。
Slave側が昇格前にfailover_logへのinsertが実行される場合、pg_keeper.after_commandのsleepを大きくする。

pg_keeper.after_command = 'sleep 5 ; psql -d pg_state -c "insert into failover_log values(`date +%s`, \'`hostname`\');" -x'

「さんあ~る」からゴミ捨てカレンダーをスクレイピングする

4月に千葉県柏市のゴミ捨てアプリ「さんあ〜る」が、Web版としてリリースされました。

ごみ分別アプリ「さんあ~る」がインターネットでも利用できます!

さんあ〜るのごみカレンダーをiframeとしてWPに引っ張ってこようと思ったけど拡縮の問題があり挫折。
あと、画像がいらないな、と思ったのでpython3でスクレイピングしてみた。

# coding: UTF-8
import datetime
import urllib.request
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
from bs4 import BeautifulSoup

today = datetime.date.today()
year = today.strftime("%Y")
month = today.strftime("%m")

# アクセスするURL
# XXXXXは地区番号らしい
url = 'https://manage.delight-system.com/threeR/web/calendar?jichitaiId=kashiwashi&areaId=22125&year={year}&month={month}'.format(year=year, month=month)

html = urllib.request.urlopen(url)
soup = BeautifulSoup(html, "html.parser")

table = soup.find_all("table")
cal = []
for tag in table :
    try:
        #import pdb; pdb.set_trace()
        days = tag.find_all("td")  # カレンダーのセル数(7日×週)
        for day in days:
            span = day.find_all('span')
            tmp = []
            if len(span) > 0  :
                for num in range(len(span)):
                    try:
                        if span[num].get("class")[0] in ('common','sat','sun'): 
                            tmp.append(span[0].string)           # 日
                            tmp.append(span[0].get('class')[0])  # 曜

                        elif span[num].get("class")[0] in 'trash_kind_name': # ゴミ種類
                            tmp.append(span[num].string)
                        cal.append(tmp)
                    except:
                        pass
            else : # 空白セル
                cal.append([''])
    except:
        pass

print(cal)

後で、オリジナルのカレンダーの情報に充てがう予定なのでlistに入れる。

結果

[[''], [''], [''], [''], [''], ['1', 'common'], ['2', 'sat'], ['3', 'sun'], ['4', 'common', '可燃ごみ'], ['4', 'common', '可燃ごみ'], ['5', 'common', '不燃ごみ'], ['5', 'common', '不燃ごみ'], ['6', 'common', '容器包装プラスチック類'], ['6', 'common', '容器包装プラスチック類'], ['7', 'common', '可燃ごみ'], ['7', 'common', '可燃ごみ'], ['8', 'common'], ['9', 'sat'], ['10', 'sun'], ['11', 'common', '可燃ごみ'], ['11', 'common', '可燃ごみ'], ['12', 'common'], ['13', 'common', '資源品', '容器包装プラスチック類'], ['13', 'common', '資源品', '容器包装プラスチック類'], ['13', 'common', '資源品', '容器包装プラスチック類'], ['14', 'common', '可燃ごみ'], ['14', 'common', '可燃ごみ'], ['15', 'common'], ['16', 'sat'], ['17', 'sun'], ['18', 'common', '可燃ごみ'], ['18', 'common', '可燃ごみ'], ['19', 'common', '不燃ごみ'], ['19', 'common', '不燃ごみ'], ['20', 'common', '容器包装プラスチック類'], ['20', 'common', '容器包装プラスチック類'], ['21', 'common', '可燃ごみ'], ['21', 'common', '可燃ごみ'], ['22', 'common'], ['23', 'sat'], ['24', 'sun'], ['25', 'common', '可燃ごみ'], ['25', 'common', '可燃ごみ'], ['26', 'common'], ['27', 'common', '資源品', '容器包装プラスチック類'], ['27', 'common', '資源品', '容器包装プラスチック類'], ['27', 'common', '資源品', '容器包装プラスチック類'], ['28', 'common', '可燃ごみ'], ['28', 'common', '可燃ごみ'], ['29', 'common'], ['30', 'sat']]

cal[n][1]の値は、
sat /土曜
sun / 祝祭日
common / 平日
らしい。

fluentdでMySQLにデータを入れる

https://github.com/tagomoris/fluent-plugin-mysqlを使って、fluentd-3.xでmysql 5.7にログを入れる方法のメモ

同時にbigqueryに対してもログを入れているので、@type copyを使う。

<match xxx.yyyy.accesslog>
  @type copy

  # bigquery用
  <store>
    @type             bigquery
    auth_method       json_key
    json_key          PATH/TO/FILE
    project           GCP PROJECT
    dataset           ${tag[0]}
    table             ${tag[1]}_${tag[2]}_%Y%m%d
    auto_create_table true
    schema_path       /etc/td-agent/schema.json

    <buffer tag,time>
      @type file
      path        /var/log/td-agent/buffer/papillon_accesslog
      timekey 1d
      chunk_limit_size 1000000
      queue_limit_length 128
      flush_interval 1
      retry_max_times 17
      retry_wait 1s
    </buffer>
    <inject>
      time_key time
      time_format %Y-%m-%d %H:%M:%S
    </inject>
  </store>

  # MySQL用にTimeをISO8061からDATETIMEに変換する。
  <store>
    @type record_reformer
    output_tag mysql.${tag_suffix[0]}   # tag名に「mysql」を追加
    enable_ruby true     # ruby有効化
    auto_typecast true
    <record>
      time ${require 'time'; Time.parse(record["time"]).strftime("%Y/%m/%d %H:%M:%S")} # TimeをISO8061からDATETIME
    </record>
  </store>
</match>


<match mysql.xxx.yyyy.accesslog>
    @type mysql_bulk
    host 10.254.0.xx
    database TABLE
    username USER
    password PASSWORD
    column_names time,user_id,uri,referer,remote_ip
    key_names time,user_id,uri,referer,remote_ip
    table log
    transaction_isolation_level read_committed    # 2018/5から、デフォルト値がnulになったので、指定しないとトランザクション貼れない。
    flush_interval 1s
</match>

ハマったのは、

transaction_isolation_level read_committed  

の記述の部分。

ここ以外の記述で、td-agentはちゃんと動くが、

2018-06-01 20:30:30 +0900 [warn]: #0 failed to flush the buffer. retry_time=4 next_retry_seconds=2018-06-01 20:30:30 +0900 chunk="56d92e8467c4fab0440db16ee36f0d34" error_class=Mysql2::Error error="You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1"

こんなエラーが出る。

mysql側でgeneral_logを有効にするも、

2018-06-01T20:30:46.022528+09:00           14 Connect   logger@fluentd01 on accesslog using TCP/IP
2018-06-01T20:30:46.023467+09:00           14 Query     SHOW COLUMNS FROM log
2018-06-01T20:30:46.024207+09:00           14 Quit

と、全然有用なログじゃないし。

結局、tcpdumpを取得して見たら、分離レベルを指定せずに 「SET SESSION TRANSACTION ISOLATION LEVEL」を投げている事が原因だった。

解決してよかったー

ansibleでタスクをスキップしても同名のregisterが設定される

ansibleでデプロイするタスクを書いていて遭遇した仕様の話。

やりたいことは、gitのtagやbranch名を引っ張ってきてslackに通知したい。
ステージング環境でのデプロイでも使っているタスクなので、「masterブランチのtag」が入るか、「develop/test」などのブランチが入ってきても適切に通知したい。

最初は、

# branchがmasterの場合、gittagにtag名を入れる
  - name: git status
    shell: git status | head -1 | awk '{print $2}'
    args:
      chdir: "{{ workdir }}/{{ repobase }}/{{ project }}"
    register: branch_name
    changed_when: false

  - name: check tag version
    shell: git status | head -1 | awk '{print $5}'
    args:
      chdir: "{{ workdir }}/{{ repobase }}/{{ project }}"
    register: gittag
    when: branch_name.stdout == "HEAD"
    changed_when: false


# branchがmasterではない場合、gittagにブランチ名を入れる
  - name: check branch
    shell: git status --short --branch | awk '{print $2}'
    args:
      chdir: "{{ workdir }}/{{ repobase }}/{{ project }}"
    register: gittag
    when: branch_name.stdout != "HEAD"
    changed_when: false

# slack送信
  - name : send tag (finish)
    slack:
      token: '{{ slack_token }}'
      msg: "デプロイが開始します\n
            ``` 
            project: {{project}}\n
            env: {{env}}\n
            version: {{ gittag.stdout }}\n
            date: {{ lookup(\"pipe\",\"date +%Y/%m/%d-%H:%M:%S\") }}
            ```"
      channel: '{{ post_channel }}'
      color: good
    run_once: true

と書いたが、branchがmasterで、check branchタスクがskipされているにも関わらず、register: gittagの中身が空っぽになる。
公式を確認すると、

If a task fails or is skipped, the variable still is registered with a failure or skipped status, the only way to avoid registering a variable is using tags.

タスクが失敗したり、スキップしたりした場合も変数は設定される。
らしい。

結局、以下のように修正。

  vars_files:
    - ../vars/vars.yml
  tasks:

# branchがmasterの場合、gittagにtag名を入れる
  - name: git status
    shell: git status | head -1 | awk '{print $2}'
    args:
      chdir: "{{ workdir }}/{{ repobase }}/{{ project }}"
    register: branch_name
    changed_when: false

  - name: check tag version
    shell: git status | head -1 | awk '{print $5}'
    args:
      chdir: "{{ workdir }}/{{ repobase }}/{{ project }}"
    register: gittag
    when: branch_name.stdout == "HEAD"
    changed_when: false


# branchがdevelopではない場合、gittagにブランチ名を入れる
  - name: check branch
    shell: git status --short --branch | awk '{print $2}'
    args:
      chdir: "{{ workdir }}/{{ repobase }}/{{ project }}"
    register: gitbranch
    when: branch_name.stdout != "HEAD"
    changed_when: false

# slack送信
  - name : send tag (finish)
    slack:
      token: '{{ slack_token }}'
      msg: "デプロイを開始します\n
            ``` 
            project: {{project}}\n
            env: {{env}}\n
            version: {{ gittag.stdout }}\n
            date: {{ lookup(\"pipe\",\"date +%Y/%m/%d-%H:%M:%S\") }}
            ```"
      channel: '{{ post_channel }}'
      color: good
    when: branch_name.stdout == "HEAD"
    run_once: true


  - name : send branch (finish)
    slack:
      token: '{{ slack_token }}'
      msg: "デプロイを開始します\n
            ``` 
            project: {{project}}\n
            env: {{env}}\n
            version: {{ gitbranch.stdout }}\n
            date: {{ lookup(\"pipe\",\"date +%Y/%m/%d-%H:%M:%S\") }}
            ```"
      channel: '{{ post_channel }}'
      color: good
    when: branch_name.stdout != "HEAD"
    run_once: true

上手い書き方無いかなぁ

CentOS7のファイルディスクリプタの設定

確認方法

cat /proc/`pgrep -f サービス名`/limits

Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             29222                29222                processes 
Max open files            1024                1024                files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       29222                29222                signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us        

変更方法

/usr/lib/systemd/system/サービス管理ファイル に、

LimitNOFILE=65536

を追加する。

追加した跡は、

systemctl daemon-reload
systemctl restart daemon

として、サービスを再起動する。

pecoで遊んでみる

Twitterでやり取りさせて貰っているShu1さんの記事が面白かったので、GCEで再現してみた
http://blog.jicoman.info/2018/04/ec2-ssh-using-peco/

※ gcloudの設定が終わっている事前提

pecoインストール

wget https://github.com/peco/peco/releases/download/v0.5.3/peco_linux_amd64.tar.gz

tar zxvf peco_linux_amd64.tar.gz
mv peco_linux_amd64/peco /usr/local/bin/
rm -rf peco_linux_amd64*

関数設定

vim ~/.bash_profile

# ssh簡単にするやつ
function ssh-gce() {
  local user="root"
  local host=$(gcloud compute instances list | grep stg | awk '{print $1,$3,$4}' | column -t -s" " | /usr/local/bin/peco | awk '{print $3}')
  ssh "$user@$host"
}

修正後に、

source ~/.bash_profile

出来たー!