GitHub ActionsでLOCALEがja_JP.UTF-8のPostgreSQLを使用する方法
結論
- サービスコンテナでLOCALEに
ja_JP.UTF-8
を設定することはできない - 自力でLOCALEを追加するイメージを作って、
docker run
で起動する
Dockerfile
FROM postgres:11.5 RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
GitHub Actionsのワークフロー設定
- 正しい呼び名がわからず
name: postgresql on: [push] jobs: postgresql: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: PostgreSQL container build & run run: | docker build -t postgresql_i .github/workflows docker run -d --name postgresql_t -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e LC_ALL=ja_JP.UTF-8 postgresql_i - name: wait for db run: until docker exec postgresql_t pg_isready -U postgres; do sleep 1; done - name: show locale run: docker exec postgresql_t psql -U postgres -c "SHOW LC_COLLATE;"
ファイル構成
└ .github └ workflows ├ Dockerfile └postgresql.yml
- Dockerfileはどこに置くのが良いのかわからず
.github/actions
みたいなフォルダ作ってそこに置くのが良い?
出力
Run docker exec postgresql_t psql -U postgres -c "SHOW LC_COLLATE;" lc_collate ------------- ja_JP.UTF-8 (1 行)
詳細
- PostgreSQLはデフォルトのLOCALE(
en_US.utf8
)だと日本語のソートが想定外の動きをする場合がある- 詳細は以下の記事を参照
- yamap55.hatenablog.com
- Linuxでは設定したいLOCALEである
ja_JP.UTF-8
はインストールする必要がある- Linuxのバージョンとかディストリビューションで違いがあるかは知らない
- GitHub ActionsでPostgreSQLを使用する場合、サービスコンテナを使用するのが定石な様子
- サービスコンテナ内で起動前にコマンド実行ができないようなので、LOCALEのインストールができない
- 自前でimageを作る必要がある
参考
- GitHub Support Community で行った質問
- サンプルリポジトリ
- LOCALEを
ja_JP.UTF-8
にしないと発生する問題について - GitHub Actionsのサービスコンテナ(PostgreSQL)について
PostgreSQLのデフォルトLOCALEでは日本語文字列のソート結果が想定と異なる
概要
- PostgreSQLをデフォルトのまま使用すると日本語文字列のソート結果が想定と異なる
- LOCALEを正しく設定することで修正可能
- 文字列の並び順は
LC_COLLATE
で制御されるこの設定がデフォルトだとen_US.utf8
となっていることが原因
動作確認環境
- Docker
- PostgreSQL 11.5
対応方法
FROM postgres:11.5 RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8 ENV TZ=Asia/Tokyo ENV LANG=ja_JP.UTF-8 ENV LANGUAGE=ja_JP:ja ENV LC_ALL=ja_JP.UTF-8
詳細及び再現手順
再現
起動
docker run -d --name postgres_1 postgres:11.5 docker exec -it postgres_1 psql -U postgres
SQL
create table hoge ( id int, value varchar(10)); insert into hoge values (1, 'あ'), (2, 'あ(ほげ)'), (3, 'い'), (4, 'い(ふが)') ; select * from hoge order by value;
結果
postgres=# select * from hoge order by value; id | value ----+------------ 1 | あ 3 | い 2 | あ(ほげ) 4 | い(ふが) (4 rows)
LOCALEの確認
postgres=# SHOW LC_COLLATE; lc_collate ------------ en_US.utf8 (1 row)
対応
Dockerfile
FROM postgres:11.5 RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8 ENV TZ=Asia/Tokyo ENV LANG=ja_JP.UTF-8 ENV LANGUAGE=ja_JP:ja ENV LC_ALL=ja_JP.UTF-8
起動
docker build . -t yamap55/postgres:11.5_jajp docker run -d --name postgres_2 yamap55/postgres:11.5_jajp docker exec -it postgres_2 psql -U postgres
SQL
create table hoge ( id int, value varchar(10)); insert into hoge values (1, 'あ'), (2, 'あ(ほげ)'), (3, 'い'), (4, 'い(ふが)') ; select * from hoge order by value;
結果
postgres=# select * from hoge order by value; id | value ----+------------ 1 | あ 2 | あ(ほげ) 3 | い 4 | い(ふが) (4 行)
LOCALEの確認
postgres=# SHOW LC_COLLATE; lc_collate ------------- ja_JP.UTF-8 (1 行)
参考
- PostgreSQL 11.5文書: 23.1. ロケールのサポート
- 文字列の照合順序(Collation)
- 何故デフォルトLOCALEであのような順序になるかは↓参照
- http://www.nminoru.jp/~nminoru/programming/collation.html
背景とか蛇足とか
- GitHub ActionsでPostgreSQLを使用したテストを行おうと、サービスコンテナを使用した結果この事象に遭遇した。
- Linuxでは(バージョンとかディストリビューションで違いがあるかは知らない)デフォルトでは
ja_JP.UTF-8
がないようなのでPostgreSQLの設定だけ行っても起動時にエラーとなる。- ↑のDockerfileに書いたようにlocaledefで追加する必要がある
- で、サービスコンテナではコマンドの実行などはできないようなので、結局自前でDockerfileを書く必要があるみたいです。
- https://github.community/t/167530
- 別の記事に書
く予定いた。
MySQLでも試した
起動、接続
docker run --name mysql_1 -e MYSQL_ROOT_PASSWORD=mysql -d mysql docker exec -it mysql_1 mysql -u root -p -h 127.0.0.1 -D mysql -pmysql
結果
mysql> create table hoge ( id int, value varchar(10)); Query OK, 0 rows affected (0.04 sec) mysql> insert into hoge values -> (1, ''), -> (2, ''), -> (3, ''), -> (4, '') -> ; Query OK, 4 rows affected (0.01 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select * from hoge; +------+-------+ | id | value | +------+-------+ | 1 | | | 2 | | | 3 | | | 4 | | +------+-------+ 4 rows in set (0.00 sec) mysql>
- デフォルトのLOCALEだとそもそも日本語が入らない
- 軽く調べたらPostgreSQLと同じくLOCALEを指定すれば良い様子(未確認)
AtCoder用Python環境を作った
概要
最近AtCoderを始めたのでPython用の環境を作りました。 割といい感じにできた気がしましたのでTemplate Repositoryにしています。これから始める方、AtCoder上で書いている方などは是非試してみてください。
一方、まだ私自身が使い込んでいないので、既に環境ある方やAtCoderをある程度やり込んでいる方には不満があるかもしれません。 何かありましたら Issue や Twitter などでご連絡頂けたら助かります。
導入ツール
- devcontainer
- VSCode, Git, DockerさえあればOK
- black
- 自動フォーマット
- online-judge-tools
- VSCode上でテストを実行
- atcoder-cli
- atcoder-python-snippets
環境作成(ローカルのVSCodeの場合)
- テンプレートリポジトリを元にリポジトリを作成
- ローカルにclone
- VSCodeで開く
- DevContainerで開く
※この文章でわからなければ README を参照してください。
環境作成(GitHub Codespacesの場合)
- テンプレートリポジトリを元にリポジトリを作成
- GitHubで作成したリポジトリを開く
- Code → Open with Codespaces → New codespaces
※特にCodespaces用の設定はしていないので不具合があったら教えてください
回答までの流れ
※VSCode内のターミナルでコマンドを実行します
- ログイン
acc login
oj login https://atcoder.jp/
- contestID を取得
https://atcoder.jp/contests/abs
の場合、abs
- ディレクトリ作成(問題を選択)
acc new ${contestID}
- 例:
acc new abs
- 回答する問題のディレクトリに移動
cd {contestID}/{問題}
- 回答を作成
main.py
に回答を記載
- 回答をテスト
ojt
- ※
oj t -c "python main.py"
と同じ
- 回答を提出
acc submit
acc s
と同じ
使用例
acc new abs cd abs/practicea/ vi main.py ojt acc s
QA
テンプレートファイルを変更したい
templates/py/main.py
を変更してください
独自のスニペットを追加したい
.vscode/python.code-snippets
を作成し、以下のように記載する
{ "input number": { "prefix": ["input-n"], "body": ["import sys\nn = int(sys.stdin.buffer.readline())"], "description": "input number." } }
Django REST Framework 条件に応じてAPI処理を切り替える方法
全然サンプル見つからなかったので誰かに役に立つかも?と、妥協点はあるもののとりあえず実装としては良さそうなのでメモ
やりたかったこと
- 条件によって特定のAPI処理全体を切り替えたい
- 複数発生した場合を考えると
if hogeflag:
みたいな事はやりたくない
- 複数発生した場合を考えると
- この条件というのがログインユーザ毎、特定のデータの場合という事ではなく、環境変数や設定ファイルなど動作する環境毎に切り替えたい。
- 切り替わったら、その環境では選択されなかった処理は一切使用される事はない
具体的な例とか
- アプリケーションがパッケージ販売されていて、特定の環境では処理を変更したい
- 拡張機能などがあり、特定の処理を任意で上書きたい
対応方法
概要
DjangoのMiddlewareを使用する。
Middlewareとは、実際の処理の前後に行わせることができる処理です。hookとか言ったりします。
settings.py
に MIDDLEWARE = []
と配列として記載する事で設定しますので、実際のアプリケーションで使われている事が確認できるかと思います。認証処理などもここで行っています。
詳細
# extensions.test_middleware from django.http import JsonResponse from rest_framework.request import Request from extensions.hoge import HogeView class SimpleMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) return response def process_view(self, request, view_func, view_args, view_kwargs): # if view_func.__name__ == 'HogeView': # Classで比較する場合 if request.path == '/api/v1/hogehoge/': # URLPATHで比較する場合 # DjangoのRequestとDRFのRequestが異なるため変換 # django.core.handlers.wsgi.WSGIRequest -> rest_framework.request.Request req = Request(request) res = HogeView.get(HogeView, req) # process_viewではdjango.http.Responseを返す必要があり、 # rest_framework.response.Responseをそのまま返す事ができないため、値を取得して変換している return JsonResponse(res.data, status=res.status_code) else: # Noneを返す事で既存の処理が行われる return None
# extensions.hoge.HogeView from rest_framework.response import Response from rest_framework.views import APIView class HogeView(APIView): def get(self, request): return Response({'aaa': 'bbb'})
# settings.py MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'extensions.test_middleware.SimpleMiddleware' ]
コードの実物に近い形
直接クラス名とか書いていたら、各処理にifと書くのと何にも変わらない。 ので、設定系は全部DBに突っ込んで、DBの内容と合致したら設定に従ってリフレクションで処理を呼ぶようにした。
class SimpleMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): return self.get_response(request) def process_view(self, request, view_func, view_args, view_kwargs): extension = Extension.objects.filter(class_name=view_func.__name__).first() if extension: _cls = getattr(importlib.import_module(extension.module_name), extension.class_name) method = getattr(_cls, request.method.lower()) return JsonResponse(method(_cls, Request(request)).data, status=res.status_code)
没とした案
urls.pyで対応
実装して動作するところまでは確認
詳細
urlpatterns
は先勝ち(ドキュメントは調べてない!)なので、既存処理の設定をする前に独自処理のパターンをどこからか読み込んで設定すれば既存処理を上書きする事ができる。
没とした理由
ユニットテストが大変。
実際にはDBに設定が入っている事を想定していたため、urls.py のurlpatternsの設定する所でDBアクセスする必要がある。
- エラー処理の対応が必要
- url.pyはDjangoの基本機能らしく、
python manage.py migration
などでも処理が行われるので、migration前にテーブルがあるわけないのでエラー(ProgramingError)となる。 - exceptして対応する事も可能は可能。(1度は実装した)
- url.pyはDjangoの基本機能らしく、
- ユニットテストでエラーとなる
参考
自宅Raspberry Pi再構築メモ
自宅のRaspberry Piを再構築したのでメモです。既存のRaspberry Piのスクリプト関連はGitHubにあったものの、環境関連の情報が何も残っていなかったので新規に記事に起こしています。(文章にした記憶はあるものの見つからず)
完全に自分用なので、本来ならば別の記事に分けたほうが良いものも多数あり、読みにくいと思いますがご了承ください。
また、そもそもGUIいらなかったのではないかとか、先にSSH設定して全部母艦からやればよかったのではないかとか、色々ありますがその辺りは次回構築時に改善していく予定、(いつ?)
(GUIについては、以前CUIでWifi設定に手こずったのが、一瞬でできたのでそれだけでも入っていてよかったと思う。)
※随時更新予定(最終更新 : 2020/06/16)
環境
- Raspberry Pi 3 Model B
- Raspberry Pi Imager v1.2
$ cat /etc/debian_version 10.4 $ cat /etc/issue Raspbian GNU/Linux 10 \n \l $ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 10 (buster) Release: 10 Codename: buster $ uname -a Linux raspberrypi 4.19.97-v7+ #1294 SMP Thu Jan 30 13:15:58 GMT 2020 armv7l GNU/Linux
基本設定
起動まで
- Raspberry Pi Imagerインストール
- https://www.raspberrypi.org/downloads/
- 今は自分でSDカードをフォーマット、書き込む必要ないらしい。
- Raspbian FullをSDカードに書き込み
- Raspbian(other) -> Raspbian Full
- 通常版との差は調べてないが、あまり深くいじるつもりもないのでFULLを選択
- 参考 : https://www.souichi.club/raspberrypi/raspberry-pi-imager/
- Macがスリープになってしまうと止まるのでスリープにならないようにして放置
- Raspberry Pi本体にSDカードにカード設定
- GUIが立ち上がり、設定を聞いてくるので設定
- 一応参考 : https://qiita.com/katsusuke/items/4f3c7fca08801debaf53
Set Up Screen
までは同じで、その後Wifi設定聞いてきたので設定して、そのままUpdate Softwareを実行。- 結構な時間かかる
- 再起動
ユーザ関連
- ユーザの整理
- rootのパスワード変更
sudo passwd root
- mainで操作するユーザ追加
sudo adduser ${username}
- 追加したユーザにpiユーザと同じグループを紐付ける
groups pi
- 出力 :
pi : pi adm dialout cdrom sudo audio video plugdev games users input netdev spi i2c gpio
- 出力 :
sudo usermod -G pi,adm,dialout,cdrom,sudo,audio,video,plugdev,games,users,input,netdev,spi,i2c,gpio ${username}
- rootのパスワード変更
SSH関連
- 別のマシンからSSH接続
- 左上のアイコン → 設定 → Raspberry Pi の設定 → インターフェイス
- SSHを有効
- ついでにカメラも有効
- 再起動
ifconfig
でIPを確認- 別のマシンから
ssh ${username}@192.168.xxx.xxx
で接続
- SSHの鍵認証設定
- 鍵作成(母艦)
ssh-keygen -t rsa
- scpでRaspberry Piに公開鍵を送る
scp ~/.ssh/raspberry_rsa.pub ${username}@192.168.xxx.xxx:~
- 公開鍵を設定(Raspberry Pi)
mkdir ~/.ssh
chmod 700 ~/.ssh
cat ~/raspberry_rsa.pub >> .ssh/authorized_keys
chmod 600 .ssh/authorized_keys
rm ./raspberry_rsa.pub
- 鍵作成(母艦)
- SSHのセキュリティとか(Raspberry Pi)
- 設定ファイル開く
sudo vi /etc/ssh/sshd_config
- ポート番号変更
Port 60522
- 鍵認証の有効化
PubkeyAuthentication yes
- パスワード認証無効化
PasswordAuthentication no
- 鍵認証が正しく設定されているか確認してからの方が良い
- rootログインの禁止も各種サイトには書かれていたが、今のバージョンではデフォルト無効になっている?
- 不安だったので
PermitRootLogin yes
としてrootでログインできてしまうことを確認した上で、下の設定を追加 PermitRootLogin no
- 不安だったので
- sshデーモンを再起動
sudo /etc/init.d/ssh restart
- 空パスワードを無効
PermitEmptyPasswords no
- 設定ファイル開く
- 公開鍵でアクセス(母艦)
- 試行
ssh -i ~/.ssh/raspberry_rsa -p 60522 ${username}@192.168.xxx.xxx
- configに設定追加
vi ~/.ssh/config
- 内容は下記参照
- 試行2
ssh raspi
- 試行
- SSHの設定確認(母艦)
- パスワードで接続できないことを確認
ssh -p 60522 ${username}@192.168.xxx.xxx
- パスワードで接続できないことを確認
Host raspi HostName 192.168.xxx.xxx User ${username} Port 60522 IdentityFile ~/.ssh/raspberry_rsa
参考
- Raspberry Pi Imager Downloads
- Raspberry Pi ImagerでOS(Raspbian)インストール
- ラズパイでやらなければいけない4つのセキュリティ対策!
- SSHサーバの設定(ポート番号変更、rootのログイン禁止、パスワード認証禁止)
- ラズパイにSSH接続(鍵認証)
ホスト名関連
- defaultは
raspberrypi
なのでわかりやすく変更しておく - 設定変更
sudo vi /etc/hostname
sudo vi /etc/hosts
- 再起動
sudo reboot
- 確認
hostname
- SSHの設定もIPだと変更される可能性があるのでホスト名でアクセスできるように変更しておく
- 試行
ssh -i ~/.ssh/raspberry_rsa -p 60522 ${username}@${hostname}.local
- configに設定追加
vi ~/.ssh/config
- 内容は下記参照
- 試行
Host raspi HostName ${hostname} User ${username} Port 60522 IdentityFile ~/.ssh/raspberry_rsa
参考
ディスプレイ装着
- 2年以上前(2018/01/29)に購入したものの放置してたディスプレイを接続する
- Kuman Raspberry Pi 3 2用ディスプレイ タッチパネル 3.5インチ 320*480 SPI インターフェース Raspberry Pi Model B B+ A+ A SC06
- https://www.amazon.co.jp/gp/product/B01FU5P2HA/
手順
- GPIOピンに差し込む
- 一番目立つピンに多分そうだろうと思う感じで挿せば動いた
- 以下の手順でドライバをインストール
- sshで接続しているとインストール後にログアウトするので注意
git clone https://github.com/waveshare/LCD-show.git cd LCD-show/ chmod +x LCD35-show ./LCD35-show
詳細
- DVD?CD?が付いていたが無視(そもそもドライブがない)
- 中身はドライバらしい
- Amazonのレビューを見るとこの商品はパチもんだが、Waveshareのドライバを使えば動くという情報を得る
- 他でも詳細情報を得る
- Waveshareのドライバインストール手順通りに実行
喋らせる
- open-jtalkをインストール
sudo apt-get update sudo apt-get install open-jtalk open-jtalk-mecab-naist-jdic hts-voice-nitech-jp-atr503-m001
- 声を変更していたので
mei_normal.htsvoice
を取得してくる- 全然記憶にないが、昔はどこかにセットがあった??
- 正しいルートはMMDAgentの中にあるVoiceを使用する
- Raspberry Piからだとうまく取得できなかったので別の手段を取る
- GitHubでファイル名検索をしてファイルを持ってくる
filename:mei_normal.htsvoice
- 実際に喋らせる部分は既存スクリプトをそのまま使用
参考
ローカルのVSCodeでRaspberry Piの上コードを編集する
拡張機能インストール
接続
- 左にあるアイコンが並んでいる部分から
PCに<>
となってるアイコンクリック- リモートエクスプローラ
- SSH Targets -> raspi を選択
- しばらくしたら別WindowでVSCodeが起動する
- TerminalタブでRaspberry Piに接続されているか確認
- 左にあるアイコンが並んでいる部分の一番上エクスプローラクリック
- OPEN FOLDER から指定のフォルダを開く
参考
USBカメラで写真を撮る
- apt-get update
sudo apt-get update
- 静止画取得用モジュールインストール
sudo apt-get install v4l-utils fswebcam
- カメラの接続確認
lsusb
- Webカメラが接続されていることを確認
- カメラで写真撮る
fswebcam -r 640x480 ../raspberrypi-home/hoge2.jpg
-r
で解像度
Python3 環境
- Python3 のバージョン確認
python3 --version
- Python 3.7.3
- 仮想環境作成
python3 -m venv .venv
- pipのバージョンアップ
pip install --upgrade pip
- 必要ライブラリインストール
pip install -r requirements.txt
Vimの設定
- デフォルトのVimは使いにくいので変更
- 確認
dpkg -l | grep vi
- アンインストール
sudo apt-get --purge remove vim-common vim-tiny
- Vimインストール
sudo apt-get install vim
- Gitのエディタを変更
git config --global core.editor 'vim -c "set fenc=utf-8"'
- システム?のデフォルト?のエディタを変更
sudo update-alternatives --config editor
参考
BluetoothリモートシャッターとRaspberry Piのカメラを連携
- bluetooth用のライブラリインストール
sudo apt-get install bluetooth pi-bluetooth
- Bluetoothリモートシャッター用のライブラリをインストール
sudo gem install bluebutton
- https://github.com/kinnalru/bluebutton
- ※↑見たらそんなに難しくないようなのでPythonで再実装してみたい
- 現在のユーザをbluetoothグループに追加
- bluetoothctlでBluetoothリモートシャッターの認識とペアリング
- 対話式なので注意
$ bluetoothctl Agent registered [bluetooth]# power on Changing power on succeeded [bluetooth]# scan on Discovery started [NEW] Device XX:XX:XX:XX:XX:XX AB Shutter3 [bluetooth]# pair XX:XX:XX:XX:XX:XX [AB Shutter3 ]# trust XX:XX:XX:XX:XX:XX [CHG] Device XX:XX:XX:XX:XX:XX Trusted: yes
- 設定ファイル作成
vi ./bluebutton.conf
keyup=echo UP keydown=echo DOWN longup=echo LONG UP longdown=echo LONG DOWN
- 試行
sudo bluebutton -d="AB Shutter3" -c "/home/yamap55/raspberrypi-home/bluebutton.conf"
- リモートシャッターのボタン押してメッセージが表示されればOK
- 接続が切れていたからか、反応するまで少し時間がかかることがあったので注意
- 処理を修正
keyup=/home/yamap55/raspberrypi-home/script/takePhoto.sh >> /home/yamap55/raspberrypi-home/logs/takePhoto.log 2>&1
- デーモン起動
sudo bluebutton -d="AB Shutter3" -c "/home/yamap55/raspberrypi-home/bluebutton.conf" &
- OS起動時に常駐するように設定
vi /etc/rc.local
exit 0
の前辺りに追加sudo bluebutton -d="AB Shutter3" -c "/home/yamap55/raspberrypi-home/bluebutton.conf" &
参考
- ラズパイ3 + リモートシャッター(Remote Shutter Control)
- Sony MESH Hubでミクさんにおかえりを言ってもらった
- Linux のコマンドラインで Bluetooth 接続
- bluetoothctlのコマンド一覧が助かった
通信速度が原因で「apt-get」が失敗する事がある
タイトルだけ見るとそりゃそうだろという話ではあるのですが、いきなり失敗するようになってかなりハマったのでメモ。 そもそも通信速度が原因という事に気づくまでにかなりの時間がかかった。
参考までに、状況が発生した環境で通信速度を調べたところ、1Mbps位でした。( fast.com で測定)
解決方法
apt-getのオプションでタイムアウトを指定する。
apt-get -o Acquire::http::Timeout="300" update
※指定時間の単位は「秒」との事
設定ファイルに書く場合
設定ファイルでの指定も可能(後述するがコマンドでのオプション指定よりこちらの方が良い)
- ファイルPATH :
/etc/apt/apt.conf.d
- ファイル名 :
99timeout
何でも良いと思われる
Acquire::http::Timeout "300"; Acquire::ftp::Timeout "300";
Dockerfile
今回はdocker内で発生したため、Dockerfileのサンプルをメモ
FROM ubuntu:18.04 RUN /bin/echo -e "Acquire::http::Timeout \"300\";\n\ Acquire::ftp::Timeout \"300\";" >> /etc/apt/apt.conf.d/99timeout RUN rm -rf /var/lib/apt/lists/* \ && apt-get update \ && apt-get -y install wget
※参考 : Dockerfileで複数行を改行付きでechoする際にハマったので共有しておきます
※ubuntuのデフォルトシェルであるdashのbuild inされているechoだと echo -e
は使えないので注意。(-e
がそのままファイルに出力されてoptionエラーになる)
ログ
C:\Users\yamap55>docker run --rm -it ubuntu:18.04 /bin/bash root@0bbdb818123f:/# apt-get update Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB] Get:2 http://security.ubuntu.com/ubuntu bionic-security/restricted amd64 Packages [31.0 kB] Get:3 http://security.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages [7641 B] Get:4 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [824 kB] Get:5 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [836 kB] Get:6 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB] Get:7 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB] Get:8 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB] Get:9 http://archive.ubuntu.com/ubuntu bionic/multiverse amd64 Packages [186 kB] Get:10 http://archive.ubuntu.com/ubuntu bionic/main amd64 Packages [1344 kB] Ign:11 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages Get:12 http://archive.ubuntu.com/ubuntu bionic/restricted amd64 Packages [13.5 kB] Get:13 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [1128 kB] Get:14 http://archive.ubuntu.com/ubuntu bionic-updates/restricted amd64 Packages [44.7 kB] Get:15 http://archive.ubuntu.com/ubuntu bionic-updates/multiverse amd64 Packages [11.7 kB] Get:16 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [1351 kB] Get:17 http://archive.ubuntu.com/ubuntu bionic-backports/main amd64 Packages [2496 B] Get:18 http://archive.ubuntu.com/ubuntu bionic-backports/universe amd64 Packages [4247 B] Ign:11 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages Ign:11 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages Err:11 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages Connection failed [IP: 91.189.88.24 80] Fetched 6278 kB in 3min 24s (30.8 kB/s) Reading package lists... Done E: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/bionic/universe/binary-amd64/Packages Connection failed [IP: 91.189.88.24 80] E: Some index files failed to download. They have been ignored, or old ones used instead.
※ミラーに変更してもほぼ変わりませんでした
メモ
ログに出力されているURLについて
ログに出ている http://archive.ubuntu.com/ubuntu/dists/bionic/universe/binary-amd64/Packages
にアクセスすると404になるため、サーバ側のエラーとかURLが変わったとか考えてしまった。
どうやら内部的には「Packages.gz」(もしくは「Packages.xz」)を取得しているようでこちらは存在する。( 親ディレクトリを確認するとわかる)
updateだけオプション指定してもinstallで同じように落ちるかも
updateで現象が発生した場合、コマンド実行時のオプションで解決したくなるが、実際にはupdateだけで終わる事はなく、その後installで同じように現象が発生する事となる。 勿論install 時にもオプション指定すれば解決ではあるが、このオプションが必要な場合は設定ファイルを配置するのがベターと思われる。(httpで指定が必要な場合、ftpも指定しておいた方が無難)
参考
エンジニアとして一番大事だと思う事
ドアカン Advent Calendar 2019の24日目の記事になります。
昨日はYoshihiko Morikawaさんのフィルムカメラの話です。熱いですね。*1
はじめに
いつの間にかITエンジニアとして若手からシニアと言う立場になってきた今日この頃です。(IT業界歴10年ちょっと) 社会人になりたての方やエンジニア歴が浅い方と話をする際に、エンジニアとして大事なことは?みたいな話をしたりします。 先日、そんな話をした時にうまく話すことができなかったので自分の思いを書いておこうと思います。 まぁ、俗に言うポエムです。
一番大事だと思う事
私はエンジニアとして一番大事だと思うのは「尊敬する人を作る事」だと考えています。
尊敬とは色々意味にとれますが、自分が将来この人のようになりたいと強く思う人という感じです。 ここで大事なのは、自分が目指すかどうか、なれるかどうか。
世の中には天才という方がいて、凄いと思うし憧れるが絶対に自分はなれない人という人がいますが、そういう人は該当しません。
つまり、尊敬する人とは、今は自分の力では及びないが、いつかは辿り着きたい目標である存在です。
なんで大事?
なぜ、尊敬する人は大事なのかというと、自分が成長できるから。
- 人は目標があると頑張れます。
- 頑張ると成長します。
- 成長すると褒めてくれます。
- 褒められると頑張ります。
っという良い循環が発生するからです。 常に意識し、良いところは学んでいく。(そうでない所は見ないふり) そして、いつか横に並ぶ事を夢見て一歩づつ進みましょう。必ず自分の成長に繋がります。
尚、3つめは異論がありそうですが、尊敬していることを伝え、頑張っていることを伝えたら必ず褒めてくれます。 自分を尊敬してくれている人は可愛く見えますし、その人が頑張っていたら褒めるに決まっている。アピール大事。
尊敬される側も成長する(はず)
自分を尊敬している人が頑張っている ↓ 自分も頑張らないと! ↓ 成長する
っとなるはず。
私の場合
IT業界で最初に所属した会社の先輩(上司)が尊敬する人になります。 この方が上司になった時の私はどうしようもない方のITエンジニアでした。自分で勉強することもなく、指示されたことを作業するだけだったと思います。また、ずっと現場常駐だった事もあり社内で付き合いがある人もいない状態でした。当然評価も良くなかったでしょう。 そんな私を指導してくれたのがこの先輩です。
所属会社は典型的なn次請けSIerで、かなりの割合で外部会社に常駐しておりました。当然帰属意識も薄く、会社の改善や技術交流などは全く行われておりません。 そんな中孤軍奮闘して勉強会やLT会などを開催している方でした。
IT関連の情報収集の仕方から、LT資料の作り方、blogの書き方、エンジニアとして生きていくにはといった所までほんと基礎の基礎から教えていただきました。
特に最初のうちはこの方も残業続きで土日も出勤している中で、週1帰社した上で22時までMTGと称した上記の指導などをして頂きました。今から考えてもほんと頭が上がりません。
その後、先輩も私も転職しましたが、もくもく会など各種イベントに誘って頂き、現在でも私に影響を与えてくれております。
おわりに
冒頭にも記載しましたが、この記事はドアカン Advent Calendar 2019の24日目の記事になります。 このアドベントカレンダーのテーマは「自分の好きなこと」です。
私が大好きな先輩が楽しいクリスマスを迎えられますように。
*1:このアドベントカレンダーはみんな熱すぎる