- 投稿日:2021-05-09T23:19:31+09:00
Golangのテストカバレッジを効率的に確認する
Golangのテストカバレッジを効率的に確認する 前回の記事でテストカバレッジをシェルスクリプトにしてそれを実行することで確認していました。 https://qiita.com/k_yuda/items/86f40bdf3e040560ade4 今回これをDockerfileとMakefileにまとめてよりテストカバレッジを確認しやすいようにしたメモ。 流れ マルチステージビルドのstage1においてテストカバレッジを確認するためのcover.outなどを生成する stage2において、stage1のファイルをコピーする Dockerコンテナーないにあるファイル、cover.outをhtmlにコンバートしたファイルをローカルにコピーする Makefileで各種コマンドをまとめる マルチステージビルドを実現しているDockerfileを記述し直す。 Dockerfile FROM golang:latest AS stage1-buildphase WORKDIR /go/src COPY . . RUN go test main_test.go main.go -v RUN go build -o tail main.go RUN go test main_test.go main.go -coverprofile=cover.out RUN go tool cover -html=cover.out -o convert.html FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root COPY --from=stage1-buildphase /go/src/ . CMD ["./start.sh"] ここで生成されるconvert.htmlはグラフィカルにテストカバレッジを確認することができます。 Makefileで各種コマンドをまとめる Makefile NAME := gotail NAME-C := gotailcheck .PHONY: all all: docker-build docker-run .PHONY: docker-build docker-build: docker build -t $(NAME) . .PHONY: docker-run docker-run: docker run -t $(NAME) check: docker-build docker-run-covercheck open clean docker-run-covercheck: docker run --rm --name $(NAME-C) -itd $(NAME) /bin/sh docker cp $(NAME-C):/root/convert.html $(shell pwd) docker stop $(NAME-C) cp convert.html $(shell pwd)/coverchecklog/$(shell date +"%Y%m%d%I%M%S").html .PHONY: open open: open convert.html .PHONY: clean clean: sleep 10 rm -f cover.out convert.html このように記述すると/coverchecklogにテストカバレッジを確認できるhtmlファイルを保存し、自動でブラウザを立ち上げて確認できます。 docker-run-covercheck: docker run --rm --name $(NAME-C) -itd $(NAME) /bin/sh docker cp $(NAME-C):/root/convert.html $(shell pwd) docker stop $(NAME-C) cp convert.html $(shell pwd)/coverchecklog/$(shell date +"%Y%m%d%I%M%S").html docker run --rmでdockerイメージを処理が終わった後に自動で削除してくれます。 また、--nameオプションを使用することで、IDではなくてnameでdocker cpを実行することができます。 dockerのcpが終わったらイメージを停止します。 最後に現在の時間をファイル名として、coverchecklogにコンバートされたhtmlを記録します。 cp convert.html $(shell pwd)/coverchecklog/$(shell date +"%Y%m%d%I%M%S").html 全ての設定が終わったら、次のコマンドでテストカバレッジを瞬時に確認でき、記録も残してくれます。 make check これでテストカバレッジを意識した開発を手軽に行うことができそうです。 最後に 今回はdocker cpの使い方に詰まっておりました、dockerコマンドは結構覚えることが多いのでたまに混乱してしまうのですが、Makefileにまとめておくと安心です。 まだまだgolangは始めたばかりで分からないことばかりですが、golangにおけるMakefileの記述のベストプラクティスを追求していきたいと思います。
- 投稿日:2021-05-09T23:19:31+09:00
Golang のテストカバレッジを効率的に確認する
Golang のテストカバレッジを効率的に確認する 前回の記事でテストカバレッジをシェルスクリプトにしてそれを実行することで確認していました。 https://qiita.com/k_yuda/items/86f40bdf3e040560ade4 今回これをDockerfileとMakefileにまとめてよりテストカバレッジを確認しやすいようにしたメモ。 流れ マルチステージビルドのstage1においてテストカバレッジを確認するためのcover.outなどを生成する stage2において、stage1のファイルをコピーする Dockerコンテナーないにあるファイル、cover.outをhtmlにコンバートしたファイルをローカルにコピーする Makefileで各種コマンドをまとめる マルチステージビルドを実現しているDockerfileを記述し直す。 Dockerfile FROM golang:latest AS stage1-buildphase WORKDIR /go/src COPY . . RUN go test main_test.go main.go -v RUN go build -o tail main.go RUN go test main_test.go main.go -coverprofile=cover.out RUN go tool cover -html=cover.out -o convert.html FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root COPY --from=stage1-buildphase /go/src/ . CMD ["./start.sh"] ここで生成されるconvert.htmlはグラフィカルにテストカバレッジを確認することができます。 Makefileで各種コマンドをまとめる Makefile NAME := gotail NAME-C := gotailcheck .PHONY: all all: docker-build docker-run .PHONY: docker-build docker-build: docker build -t $(NAME) . .PHONY: docker-run docker-run: docker run -t $(NAME) check: docker-build docker-run-covercheck open clean docker-run-covercheck: docker run --rm --name $(NAME-C) -itd $(NAME) /bin/sh docker cp $(NAME-C):/root/convert.html $(shell pwd) docker stop $(NAME-C) cp convert.html $(shell pwd)/coverchecklog/$(shell date +"%Y%m%d%I%M%S").html .PHONY: open open: open convert.html .PHONY: clean clean: sleep 10 rm -f cover.out convert.html このように記述すると/coverchecklogにテストカバレッジを確認できるhtmlファイルを保存し、自動でブラウザを立ち上げて確認できます。 docker-run-covercheck: docker run --rm --name $(NAME-C) -itd $(NAME) /bin/sh docker cp $(NAME-C):/root/convert.html $(shell pwd) docker stop $(NAME-C) cp convert.html $(shell pwd)/coverchecklog/$(shell date +"%Y%m%d%I%M%S").html docker run --rmでdockerイメージを処理が終わった後に自動で削除してくれます。 また、--nameオプションを使用することで、IDではなくてnameでdocker cpを実行することができます。 dockerのcpが終わったらイメージを停止します。 最後に現在の時間をファイル名として、coverchecklogにコンバートされたhtmlを記録します。 cp convert.html $(shell pwd)/coverchecklog/$(shell date +"%Y%m%d%I%M%S").html 全ての設定が終わったら、次のコマンドでテストカバレッジを瞬時に確認でき、記録も残してくれます。 make check これでテストカバレッジを意識した開発を手軽に行うことができそうです。 最後に 今回はdocker cpの使い方に詰まっておりました、dockerコマンドは結構覚えることが多いのでたまに混乱してしまうのですが、Makefileにまとめておくと安心です。 まだまだgolangは始めたばかりで分からないことばかりですが、golangにおけるMakefileの記述のベストプラクティスを追求していきたいと思います。
- 投稿日:2021-05-09T23:11:34+09:00
Windows10 homeへのDockerインストール方法メモ
作業時期 本記事は私が2021年4月時点でDockerをインストールした時のメモです。 振り返り用。 実行環境 OS:Windows10 Home 64bit バージョン:20H2 CPU:Intel Core i7-7700HQ 2.80GHz 仮想化環境:WSL2 (Windows Subsystem for Linux 2) Docker:Docker Desktop 3.3.1 Windows10のbit版とバージョンを確認する Windows10 homeでDockerを使用するにあたり、以下条件を満たす必要があります。 Windows10が64bit版 Windows10がバージョン1903/1909以上 確認方法は以下の順番になります。 1.スタートメニューから「設定」クリック 2.「設定」画面で「システム」をクリック 3.「詳細情報」をクリックし、「システムの種類」と「バージョン」を確認 ※バージョンが1903未満の場合はWindows Updateからバージョンアップが必要 WSL2とLinuxカーネルを使用可能にする 1.スタートメニューから「Windowsシステムツール」→「コントロールパネル」→「プログラムと機能」→「Windowsの機能の有効化または無効化」とクリックしていく。 2.開かれた「Windowsの機能」で「Linux用 Windows サブシステム」と「仮想マシン プラットフォーム」にチェックを入れて「OK」して、変更が完了したら「今すぐ再起動」を実行する。 Linuxカーネルをアップデートする 下記のURLからLinuxカーネルをダウンロード後、起動してLinuxカーネルをアップデートする。 https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi Docker Desktop for Windowsインストーラをダウンロードして実行する 1.下記のURLを開き、「Get Started」→「Download for Windows」とクリックしてDocker Desktop for Windowsのインストーラをダウンロードする。 https://www.docker.com/ 2.ダウンロードしたインストーラ「Docker Desktop Installer.exe」を実行する。 3.環境の設定が表示されるので、すべてにチェックを付けて「OK」をクリックすると必要なファイル一式がダウンロードされ、インストールする。 4.インストールが完了後、「Close and log out」をクリックして再起動します。再起動後にデスクトップを確認すると「Docker Desktop」のアイコンが追加される。 参考資料 仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん
- 投稿日:2021-05-09T23:01:48+09:00
Rasberry Pi4でPLCでヨシッ!!
この記事では本格的なPLCをRasberry Pi4で構築します。 ただ信号をピコピコするだけはなくかなり本気でやります。 この記事では以下の要素技術を組み合わせて Docker OpenPLC modbus Scada 以下の動画のような現場猫がヨシッするアプリケーションを作ります。 必要なもの 構築にあたって必要なものは以下のとおりです。 Rasberry Pi4B SDカード SDカードアダプタ USBケーブル amazonでセット購入 SDカードライタ amazonで買えます USB充電器 amazonで買えます ブレッドボード LEDx1 抵抗220Ωx1 タクトスイッチx1 これらはamazonで買ったarduinoキットのものを流用 パソコン(動作環境ubuntu20.04 x86_64) 揃っているか確認してヨシッ!!しましょう。 Rasberry Pi側セットアップ Rasberry Pi OS(32-bit)のインストール Rasberry Pi4BにRasberry Pi OS(32-bit)をインストールします。 このサイト を参考に、rpi-imagerを使ってSDカードにRaspberry Pi OS(32-bit)イメージを書き込みます。 書き込みにはRasberry Pi4BではなくPCを使います。(当たり前ですね。) PCにrpi-imagerを以下のコマンドでインストールします。 sudo apt install rpi-imager インストールが完了したらSDカードライタを介してSDカードをPCに接続して以下の手順を実行します。 CHOOSE OS Rasberry Pi OS(32-bit)を選択します。 CHOOSE STORAGE 接続したSDカードを選択します。 WRITE このボタンで書き込みを開始。10分くらいかかります。 書き込みが終わったらSDカードの中身をファイルマネージャで開きます。 ssh(拡張子なし)という名前のファイルを小さい方のパーティションに配置しておきます。 これによりsshの接続ができるようになります。 その後、Rasberry PiにSDカードを差し込んで起動します。 この時、Rasberry Piにイーサネットケーブルを接続することを忘れないようにしてください。 起動が完了したらPCからラズベリーパイにssh接続します。以下のコマンドで接続できます。 ssh pi@<Rasberry Pi 4BのIPアドレス> 正常に接続するとパスワードが要求されます。パスワードはraspberryです。 Dockerのインストール 以下のリンクに従って以下のコマンドでRasberry Pi 4BにDockerをインストールできます。 sudo apt-get update && sudo apt-get upgrade curl -sSL https://get.docker.com | sh sudo usermod -aG docker pi 終わったら設定を有効化するためにRasberry Pi 4Bを再起動します。 docker-composeのインストール docker-composeがあるだけでかなりRasberry Pi 4B上でDockerを実行するのが楽になります。 Rasberry Pi OS(32-bit)にはPython3がデフォルトでインスールされています。 なので、Rasberry Pi4B上で以下のコマンドを実行すれば一発でインストールできます。 sudo pip3 install docker-compose PC側セットアップ Dockerのインストール PCにもDockerをインストールします。 Rasberry Piと同様に以下のコマンドで一発インスールできます。 sudo apt-get update && sudo apt-get upgrade curl -sSL https://get.docker.com | sh sudo usermod -aG docker <ユーザ名> docker-composeのインストール こちらもRasberry Pi 4Bと同じです。 以下のコマンドでインストールします。 sudo pip3 install docker-compose OpenPLC設定・実行 Docker設定 Rasberry Piの適当なディレクトリに以下のファイルを配置しましょう。 config.ini Dockerfile docker-compose.yml それぞれのファイルに以下のように記述します。 config.ini ; This configuration file enables configuring OpenPLC capabilities ; when the OpenPLC runtime starts. These capabilities can be configured ; without using the web front end and enable running the OpenPLC runtime ; standalone. ; ; This file must be located in the "etc" folder and must be named ; "config.ini". ; --------------------------------------------------------- ; --------------------------------------------------------- [logging] ; Level defines the minimum level for a message to appear ; as a log message. Messages are a lower level are not ; output. ; ; Level may be one of the following values, ordered from ; lowest to highest: ; trace, debug, info, warn, error level = info ; --------------------------------------------------------- ; --------------------------------------------------------- [interactive] ; The interactive server is what connects the web front end to the runtime ; You need this enabled if you want to be able to enable/disable services ; at runtime, view logs, etc. ; ; If you set this value to false and use the OpenPLC web interface to ; start the runtime, the web interface will not be able to communicate ; with the runtime. enabled = true ; --------------------------------------------------------- ; --------------------------------------------------------- [modbusslave] ; Modbus slave enables reading and writing located variables through the ; modbus interface. This starts a Modbus server (also know as a slave) ; running in the OpenPLC runtime. enabled = true ; TCP Settings ; ------------ port = 502 address = 127.0.0.1 ; How we bind located variables to modbus registers. ; This may be one of: ; sized - indicates to use the size of a located variable to determine ; the register type binding = sized ; --------------------------------------------------------- ; --------------------------------------------------------- [modbusmaster] ; Modbus master enables reading and writing located variables through the ; modbus interface. This starts capabilities to poll one or more Modbus ; servers and exchange data with the located variables. enabled = false ; We support multiple Modbus masters. Each master should specify ; a complete set of configuration information within this section. ; Different masters are identified by a postfix which includes the ; index of the master. Indices start at 0 and go up from there. ; A user defined name for the connection. This name appears in log messages. ; name.0 = 1 ; How long to wait for a response before indicating an error. ; Measured in microseconds. ; response_timeout.0 = 100000 ; The rate at which to poll the server. Measured in microseconds. ; The actual poll rate may be greater than this depending on response times ; from the remote server and availability of resources on the local host. ; poll_interval.0 = 250000 ; The protocol to use for connection. This value must be one of: ; tcp ; rtu ; If you set this to any other value, then this configuration item group ; is not created. You might use this to disable connecting to a particular ; Modbus slave. ; protocol.0 = tcp ; When there are communication failures, should we keep trying ; or backoff intelligently. The default behaviour is no backoff ; but you can specify one of the following: ; ; none - Same as default, no strategy. ; linear_bounded - Back off linearly based on the number of ; failed attempts. Bounded to 10x the poll ; interval. ; backoff_strategy.0 = linear_bounded ; slave_id.0 = 1 ; ip_address.0 = 127.0.0.1 ; ip_port.0 = 1000 ; rtu_baud_rate.0 = ; rtu_parity.0 = ; rtu_data_bit.0 = ; rtu_stop_bit.0 = ; discrete_inputs_start.0 = 0 ; discrete_inputs_size.0 = 1 ; coils_start.0 ; coils_size.0 ; input_registers_start.0 ; input_registers_size.0 ; holding_registers_read_start.0 ; holding_registers_read_size.0 ; holding_registers_start.0 ; holding_registers_size.0 ; --------------------------------------------------------- ; --------------------------------------------------------- [pstorage] ; The pstorage service reads and writes persistent storage. It enables ; the runtime to restore important variables to the previous value ; if the runtime is restarted. enabled = false ; How long should we wait between write cycle. The persistent storage ; checks at this rate for changes and only persists to disk if a ; value has changed within the poll period ; poll_interval = 10 ; poll_interval = 10 ; --------------------------------------------------------- ; --------------------------------------------------------- [dnp3s] ; The dnp3s enables a DNP3 outstation. enabled = false ; Location Bindings ; ----------------- ; Bind OpenPLC bit-sized output 0.0 to DNP3 binary input at index 0 ; Note that the second hierarchical index must be 0 ; bind_location = name:%QX0.0,group:1,index:0, ; Bind OpenPLC word-sized output 2 to DNP3 analog input at index 1 ; bind_location = name:%QW2,group:30,index:1, ; Bind OpenPLC word-sized output 2 to DNP3 analog output status at index 1 ; bind_location = name:%QW2,group:40,index:1, ; Bind OpenPLC long word-sized output 2 to DNP3 analog input at index 10 ; bind_location = name:%QL2,group:30,index:10, ; Bind OpenPLC bit-sized input 0.0 to DNP3 analog input at index 10 ; bind_location = name:%IX0.0,group:12,index:0, ; bind_location = name:%IX1.0,group:12,index:1, ; Bind OpenPLC word-sized input 2 to DNP3 analog command at index 0 ; bind_location = name:%IW2,group:41,index:0, ; TCP Settings ; ------------ ; address = 127.0.0.1 ; port = 20000 ; Link Settings ; ------------- ; The remote and local address ; local_address = 10 ; remote_address = 1 ; Keep alive timeout. A value in seconds, or the keyword MAX ; keep_alive_timeout = MAX ; Parameters ; ---------- ; Enable unsolicited reporting if master allows it ; enable_unsolicited = true ; How long (seconds) the outstation will allow a operate ; to follow a select ; select_timeout = 10 ; max control commands for a single APDU ; max_controls_per_request = 16 ; maximum fragment size the outstation will receive ; default is the max value ; max_rx_frag_size = 2048 ; maximum fragment size the outstation will send if ; it needs to fragment. Default is the max falure ; max_tx_frag_size = 2048 ; size of the event buffer ; event_buffer_size = 10 ; Timeout for solicited confirms (milliseconds) ; sol_confirm_timeout = 5000 ; Timeout for unsolicited confirms (milliseconds) ; unsol_confirm_timeout = 5000 ; Timeout for unsolicited retries (milliseconds) ; unsol_retry_timeout = 5000 ; The rate as which data is exchanged between DNP3 and the runtime ; (milliseconds) ; poll_interval = 250 Dockerfile FROM balenalib/raspberry-pi:latest ########################################################################### # install dependency ########################################################################### USER root WORKDIR /root/ RUN apt-get update && apt-get upgrade -y RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata RUN apt-get -y install autoconf automake bison build-essential cmake flex git libtool make pkg-config python3-pip python2.7 sqlite3 sudo wget RUN wget https://project-downloads.drogon.net/wiringpi-latest.deb && sudo dpkg -i wiringpi-latest.deb RUN pip3 install flask flask-login pyserial pymodbus RUN sudo apt-get clean ########################################################################### # install open plc ########################################################################### # add openplc user RUN useradd --create-home --shell /bin/bash openplc RUN adduser openplc sudo && \ echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER openplc WORKDIR /home/openplc # compile and install open plc RUN git clone -b development https://github.com/thiagoralves/OpenPLC_v3.git WORKDIR /home/openplc/OpenPLC_v3 RUN sudo ./install.sh rpi COPY config.ini etc/config.ini ########################################################################### # configure exposed ports ########################################################################### # HTTP port EXPOSE 8080/tcp # Modbus port EXPOSE 502/tcp # DNP3 port EXPOSE 20000/tcp # EtherNet/IP port EXPOSE 44818/tcp ########################################################################### # configure entry point ########################################################################### # USER openplc USER openplc WORKDIR /home/openplc/OpenPLC_v3 CMD ["sudo", "./start_openplc.sh"] docker-compose.yml version: "3.9" services: openplc: build: . ports: - "8080:8080" - "502:502" - "20000:20000" - "44818:44818" - "44628:44628" privileged: true ファイルの配置が完了したらファイルがあるディレクトリで以下のコマンドを実行します。 sudo docker-compose build Dockerイメージがビルドされます。 回路構築 以下のようにLEDと220Ω抵抗、タクトスイッチを配線します。 LED:220ΩとGPIO14 220Ω:LEDとグラウンド タクトスイッチ:GPIO17と3V3 poser Rasberry Pi4Bのピン配置は以下のとおりです。 実行 Rasberry Pi 4Bのdocker-compose.ymlファイルがあるディレクトリで以下のコマンドを実行します。 sudo docker-compose up コマンドを実行したらOpenPLCサーバ起動します。 FirefoxまたはChromeで<Rasberry Pi 4BのIP>:8080を開くと以下のログイン画面が表示されるはずです。 username:openplc password:openplc でログインします。 HardwareのページでRasberry Piを選択し、Save Changesボタンをクリックします。 PC側で以下の内容のgenerated.stファイルを用意します。 generated.st PROGRAM Test VAR my_button AT %IX0.3 : BOOL; lamp AT %QX0.0 : BOOL; END_VAR lamp := my_button; END_PROGRAM CONFIGURATION Config0 RESOURCE Res0 ON PLC TASK task0(INTERVAL := T#20ms,PRIORITY := 0); PROGRAM instance0 WITH task0 : Hello_World; END_RESOURCE END_CONFIGURATION このファイルはStructured Textという言語記載されています。 このファイルはOpenPLC Editorを使ってラダーを変換することで得ることができますが本記事ではOpenPLC Editorの使い方は割愛します。ちなみにもとのラダーは以下のようなラダーです。 ※ Open PLC Editorのリンク https://www.openplcproject.com/plcopen-editor/ Programsタブを開きgenerated.stをアップロードし、コンパイルします。コンパイルに成功したらstart PLCでラダーを実行します。 正しくラダーが実行されればタクトスイッチを押したときだけLEDが点灯するはずです。 PC側設定 ScadaBRイメージビルド&実行 PC側ではScadaBRをセットアップします。 ScadaBRではmodbus(通信プロトコル詳細は参考文献を参照)を介してRasberry Pi4Bの信号状態を取得します。 以下のように適当なディレクトリにDockerFile、docker-compose.ymlを配置します。 Dockerfile FROM ubuntu:latest ########################################################################### # install dependency ########################################################################### USER root RUN apt-get update && apt-get upgrade -y RUN DEBIAN_FRONTEND="noninteractive" apt-get install -y tzdata RUN apt-get install -y git time sudo unzip ########################################################################### # install scadadr ########################################################################### RUN git clone https://github.com/thiagoralves/ScadaBR_Installer.git && \ cd ScadaBR_Installer && \ ./install_scadabr.sh RUN /opt/tomcat6/apache-tomcat-6.0.53/bin/startup.sh && sleep 100 RUN cd ScadaBR_Installer && \ ./update_scadabr.sh ########################################################################### # Add Neko image ########################################################################### COPY ./media/ /opt/tomcat6/apache-tomcat-6.0.53/webapps/ScadaBR/graphics/Neko/ ########################################################################### # configure exposed ports ########################################################################### EXPOSE 8080 EXPOSE 502 ########################################################################### # configure command ########################################################################### #Start the server CMD /opt/tomcat6/apache-tomcat-6.0.53/bin/startup.sh && sleep infinity docker-compose.yml version: "3.9" services: scadabr: build: . ports: - "8080:9090" - "502:502" privileged: true Dockerfileと同じ階層にmediaディレクトリを作成します。 mediaディレクトリには以下の2つの画像を配置します。 さらに画像と同じ階層にinfo.txtを配置します。 info.txt name=Neko type=imageSet #width=200 #height=200 text.x=14 text.y=2 Dockerfileのある階層で以下のコマンドを実行してDocker imageをビルドします。 sudo docker-compose build ビルドがうまく行ったら次のコマンドでScadaBRを実行します。 sudo docker-compose up ScadaBRの設定 FirefoxまたはChromeで<PCのIPアドレス>:8080/ScadaBR/にアクセスします。 以下のログイン画面が表示されるので User id:admin Password:admin でログインします。 Data sourcesのタブからModbus IPのデータソースを追加します。 この時、Data SourceのIPにRasberry Pi 4BのIPアドレス。update periodに50 msecを指定し保存します。そして、Pointsを新規に追加し、Slaveに1。RangeにCoil status。Offsetに0を指定し保存します。保存が終わったら忘れずにData SourceとPointsをEnableにしておきましょう。 次にGraphic viewsタブを開きます。新たにGraphic viewsを追加します。ComponentsにBinary graphicをしていして追加します。追加したComponentのPointを先程追加したPointに指定。さらにgraphical rendererをNekoを指定します。 保存してFull Screenにすれば以下のように仕事猫が表示された画面になります。 タクトスイッチを押すとヨシッ!!します。 参考文献 Open PLC Project Docker rasberrypi.org SOURCEFORGE:ScadaBR amazon くまみね工房 Wikipedia: Modbus The Modbus Organization
- 投稿日:2021-05-09T21:16:25+09:00
Dockerfileを使用したJenkinsのインストール
今回はDockerfileを作成してJenkinsを起動してみたいと思います。 Dockerfileとは独自のDockerイメージを作成する事が可能となるファイルです。 1つのDockerfileを用意することで、複数のサーバーに同様の設定を行うことが可能なので、互換性等に悩まされることがなくなります。 Dockerfile作成 まずは、Dockerfileを格納するディレクトリを作成します。 作成しましたら、Dockerfileの作成を行います。 mkdir <ディレクトリ名> cd <ディレクトリ名> vi Dockerfile Dockerfileの中身を以下の通りに作成します。 # ベースイメージ FROM jenkins:<タグ> # インストールしたいプラグインを指定したい場合 USER root COPY plugins.txt /usr/share/jenkins/plugins.txt RUN /usr/local/bin/plugins.sh /usr/share/jenkins/plugins.txt USER jenkins プラグインを指定する場合のplugins.txtファイルは、<プラグイン名>:<バージョン>という形式で記載します。 Dockerfileのビルドと起動 Dockerfileの作成が完了しましたら、ビルドを実行します。 Successfully builtと表示されれば完了です。 docker build -t <任意のイメージ名> . ビルド完了後、以下のコマンドを実行します。 docker run -p 8080:8080 -p 50000:50000 -v <設定保存先パス>/jenkins_home:/var/jenkins_home -d <ビルド時に指定したイメージ名> 上記コマンド実行後、しばらくしてからhttp://<サーバーIP>:8080にアクセス出来れば完了です。 なお、私の環境の場合、どうやっても何故かディレクトリのマウントがうまくいかない(マウント対象ディレクトリのオーナーを正しく変更しているのにPermission deniedで弾かれたりエラーが大量発生したり...)ので、もし対処方法が見つかればいずれ共有しようと思います。
- 投稿日:2021-05-09T20:43:48+09:00
Docker環境でmysqlを二つ立ち上げる方法
テスト環境と本番環境でDBを分けたいときがあります そんな時にDockerでDBを二つ立ち上げる方法について記載します Docker file まずは結論 version: "3.8" services: app: build: ./your/app/dockerfile depends_on: - mysql - test_mysql command: execute command ports: - '8000:8000' - '8080:8080' mysql: build: ./your/mysql/image/path environment: MYSQL_DATABASE: your_db MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" - "33060:33060" volumes: - mysql-data:/var/lib/mysql:cached phpmyadmin: image: phpmyadmin/phpmyadmin environment: - PMA_ARBITRARY=1 - PMA_HOST=mysql - PMA_USER=user - PMA_PASSWORD=password depends_on: - mysql links: - mysql ports: - 8090:80 volumes: - /sessions - ./tools/phpMyAdmin/php.ini:/usr/local/etc/php/php.ini test_mysql: build: ./your/test/mysql/image/path environment: MYSQL_DATABASE: your_test_db MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password ports: - "3307:3306" volumes: - test-mysql-data:/var/lib/mysql:cached test_phpmyadmin: image: phpmyadmin/phpmyadmin environment: - PMA_ARBITRARY=1 - PMA_HOST=test_mysql - PMA_USER=user - PMA_PASSWORD=password depends_on: - test_mysql links: - test_mysql ports: - 8091:80 volumes: - /sessions - ./tools/phpMyAdmin/php.ini:/usr/local/etc/php/php.ini volumes: mysql-data: test-mysql-data: 実行方法 注意点 すでにある環境が立ち上げ済みで、dockerファイルを追記していたら、以下のコマンドで、既存のDBデータをすべて消して再度イメージをビルドしなおさないと私の環境ではエラーになりました 絶対に本番環境ではやらないでください。データがすべて消えます //イメージとデータの削除 docker-compose down --rmi all --volumes //ビルド docker-compose build --no-cache //コンテナ立ち上げ docker-composer up 本番環境:http://localhost:8090/ テスト環境:http://localhost:8091/ で二つphpMyAdminが立ち上がっていると思います 質問や間違いがあればコメントからお願いします!
- 投稿日:2021-05-09T17:09:01+09:00
Docker 操作コマンド
様々なOS環境を用意するのに何かと便利なDockerです。 主なコマンドを振り返ってみました。 1 イメージの取得 docker pull (イメージ名) 例 centos7イメージをcentos という名前のコンテナで取得 docker pull centos:centos7 Docker はDockerイメージをもとにDockerコンテナを作成します。そこで利用したいDockerイメージをDocker Hubから入手する必要があります。 1−2 使われていないimageを一括削除する docker image prune 2 起動中のコンテナを確認 docker ps (オプション) -a を付けることで全てのコンテナを確認できます。 3 以前起動していたコンテナを起動 docker restart コンテナID 4 起動したコンテナに入る docker exec -it コンテナ名(コンテナIDでも可) コマンド名 例 docker exec -it (コンテナID) /bin/bash(コマンド名) コマンド名はPCのシェルに合わせます。bash等 これでコンテナ操作できます。 5 コンテナから抜ける exit
- 投稿日:2021-05-09T16:36:29+09:00
Rails 6 + MySQL8.0 + Docker 環境でMySQLを日本語化
初学者向けの記事です。 私の備忘録として残します。 docker-compose.yml上で2つのことをしようとしてハマった ・「MySQL8.0の認証方法に対応」 ・「MySQLの文字コードを変更」 これを同時にやろうとしてハマりました。 やりたいこと1 「MySQLの認証方法変更」 MySQL8.0から command: --default-authentication-plugin=mysql_native_password を追加する必要がありました。 コード全体を確認 (docker-compose.yml) version: '3' services: db: image: mysql:8.0 command: --default-authentication-plugin=mysql_native_password volumes: - ./src/db/mysql_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: password web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - ./src:/app ports: - "3000:3000" depends_on: - db やりたいこと2 MySQLの文字コードをutf8mb4に変えたい また、dockerでmysqlの文字コードを日本語対応のものに変更しようとすると、次のようなコマンドを打つ必要があるとわかりました。 (imageを引っ張ってくるとデフォルトの文字コードは「latin1」でした) command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci で、「commandを2つ書けば良いんだな」と思って調整していたのですが、うまくいきません。 というのも、docker-compose.ymlのcommandは「1つしか書けない」からなんですね。 Run a one-off command on a service 参考文献 思いついた解決策1(失敗):1つの長いcommandにする 下記リンクを参考に長い1つのcommandを作ろうと思いましたが失敗しました。 もう少し粘れば行ける気がするのですが、そもそも長いコマンドはあまり美しくないかも・・・と思って解決策2を試したところ、すんなり解決しました。 参考リンク 思いついた解決策2(成功):localのmy.cnfをmysqlのdbコンテナにコピーする まずlocalの適当な場所にmy.cnfを作ります。 そこにdbコンテナのmy.cnfをコピーして、先ほどコマンドでやりたかったことを追記します。 そしてdocker-compose.ymlを編集 1、commandを削除(全てmy.cnfに書いたので) 2、volumesに下記の一行追記 - ./src/db/my.cnf:/etc/mysql/my.cnf コード全体を確認 (docker-compose.yml) version: '3' services: db: image: mysql:8.0 volumes: - ./src/db/mysql_data:/var/lib/mysql - ./src/db/my.cnf:/etc/mysql/my.cnf environment: MYSQL_ROOT_PASSWORD: password web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - ./src:/app ports: - "3000:3000" depends_on: - db おわり これで無事文字コードの置き換えとMySQL8.0の認証を同時に行うことができました。 Rails 6 + MySQL8.0 + Dockerで開発をすれば誰でもこの状況になる気がするので、みなさん普通に解決してるんですよね。 私は1時間以上かかりました。 これからも精進します。 何か間違いがあればご指摘いただけますと幸いです。 備考 docker-compose.ymlを書き換えた時はdocker-compose downとupだけで動作確認できます。 私はよくわからなくて途中まで毎回buildしていました。
- 投稿日:2021-05-09T16:18:38+09:00
Laravelを調べる:Docker起動編
Laravelを調べる: Docker起動編 2021/05/09 : ただいま編集中です! 環境 Name Version OS macOS Catalina (ver 10.15.7) docker desktop version 3.2.2 準備 Docker Desktopがインストールされていれば、以下のコマンドで使い始めることが可能。(簡単!) # mysql、pgsql、mariadb、redis、memcached、meilisearch、selenium、mailhog # default : mysql、redis、meilisearch、mailhog、selenium $ curl -s "https://laravel.build/example-app?with=mysql,redis" | bash $ cd example-app $ ./vendor/bin/sail up sailコマンドでの実行/停止 実行 # フォアグラウンドで実行 $ ./vendor/bin/sail up # # バックグラウンドで実行 $ ./vendor/bin/sail up -d 停止 $ ./vendor/bin/sail down 動作確認 ./vendor/bin/sail up を実行した状態で http://localhost/ にアクセスするとLaravelのページが表示される。 起動してからsailコマンドでできること シェルを起動 $ ./vendor/bin/sail shell mysqlにログイン $ ./vendor/bin/sail mysql 展開されたファイル 展開されたファイルのうち、頻繁に使うと思われるディレクトリ (app, config, database, routes) の内容をリストアップしておく。 すでに app/Models/User.php と 2014_10_12_000000_create_users_table.php がある点に注意。 このままmidgrateするとデフォルトの状態でUserテーブルが作られる。 % tree app app ├── Console │ └── Kernel.php ├── Exceptions │ └── Handler.php ├── Http │ ├── Controllers │ │ └── Controller.php │ ├── Kernel.php │ └── Middleware │ ├── Authenticate.php │ ├── EncryptCookies.php │ ├── PreventRequestsDuringMaintenance.php │ ├── RedirectIfAuthenticated.php │ ├── TrimStrings.php │ ├── TrustHosts.php │ ├── TrustProxies.php │ └── VerifyCsrfToken.php ├── Models │ └── User.php └── Providers ├── AppServiceProvider.php ├── AuthServiceProvider.php ├── BroadcastServiceProvider.php ├── EventServiceProvider.php └── RouteServiceProvider.php % tree config config ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── cors.php ├── database.php ├── filesystems.php ├── hashing.php ├── logging.php ├── mail.php ├── queue.php ├── services.php ├── session.php └── view.php % tree database database ├── factories │ └── UserFactory.php ├── migrations │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_resets_table.php │ └── 2019_08_19_000000_create_failed_jobs_table.php └── seeders └── DatabaseSeeder.php % tree routes routes ├── api.php ├── channels.php ├── console.php └── web.php 参考 Laravelとの出会い
- 投稿日:2021-05-09T14:54:17+09:00
docker環境構築 mecab && python3 on ubuntu20.04
mecabの辞書はipadicです。 File構成 dir/ ├ Dockerfile ├ docker-compose.yml └ requirements.txt Dockerfile FROM ubuntu:20.04 USER root RUN apt update RUN apt install -y python3-pip RUN apt -y install build-essential libssl-dev libffi-dev python3-dev RUN apt -y install mecab libmecab-dev mecab-utils mecab-ipadic mecab-ipadic-utf8 python3-mecab RUN apt -y install locales && \ localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 ENV LANG ja_JP.UTF-8 ENV LANGUAGE ja_JP:ja ENV LC_ALL ja_JP.UTF-8 ENV TZ JST-9 ENV TERM xterm ADD requirements.txt . RUN apt-get install -y vim less RUN apt-get install -y libhdf5-dev RUN pip3 install --upgrade pip RUN pip install --upgrade setuptools RUN pip install -r requirements.txt requirements.txt mecab-python unidic-lite //なくても動く references Python 3をインストールしUbuntu 20.04サーバーにプログラミング環境を設定する方法 (https://www.digitalocean.com/community/tutorials/how-to-install-python-3-and-set-up-a-programming-environment-on-an-ubuntu-20-04-server-ja) 【Python】形態素解析エンジン MeCabの使い方 (https://hibiki-press.tech/python/mecab/5153) MeCab のインストール(Ubuntu 上) (https://www.kkaneko.jp/tools/ubuntu/ubuntu_mecab.html)
- 投稿日:2021-05-09T14:11:36+09:00
【M1必見】Docker を使ってデータ解析環境を構築する
なぜDocker を使うのか 結論から言うと、PCが汚れるのを防ぐため。HOSTコンピューター(自分が普段使うコンピュータ)に様々なパッケージを入れると、手間がかかるし、アンインストールしてもキャッシュが残ったりして、ストレージが少なくなってしまう。Dockerのコンテナを使い仮想環境を構築して、その中に様々なパッケージをインストールすることで、HOSTコンピュータに負荷をかけることなく、データ解析、分析が可能になる。さらに、インストールしたパッケージ同士がエラーを起こした際に、対応しやすいという利点もある。それに加えて、Dockerfileを共有することで、同じ環境が他の人でもコマンド一つで構築できてしまうという利点もある。 Dockerfile を作成する Dockerfileを作成する方法はいくらでもあるが、個人的には、https://code.visualstudio.com/ を使うことをお勧めする dockerfile # ubuntuをベースに docker image を作成する FROM ubuntu:latest # メンテナンスなどによく使われるコマンドをインストールする(-yはパッケージをインストールする際に必要なおまじない) RUN apt-get update && apt-get install -y wget vim sudo # WORKDIR でインストールする場所を決める WORKDIR <Anacondaをインストールする場所、推奨は「/opt」> RUN wget https://repo.continuum.io/archive/Anaconda3-2020.11-Linux-x86_64.sh <- インストールしたいAnacondaのバージョン Anacondaのバージョンなどについては、 https://repo.anaconda.com/archive/ を参照するといい。ubuntuに対応しているのは、「Anaconda3-2019.10-Linux-x86_64.sh」のように、「Linux-x86」が入っているもの dockerfile # anacondaインストーラーを起動し、anaconda3をインストールする # -b : バッチファイル的に動かすときに使用する(必須) # -p path :anacodna3をどこに置くかを指定する(デフォルトでは、root/anacodna3となる。メンテがめんどいので、optの下においた) RUN sh Anaconda3-2020.11-Linux-x86_64.sh -p /opt/anaconda3 -b # ENVで環境変数を設定する。以下は"python"のためのパス ENV PATH /opt/anaconda3/bin:$PATH # "jypyter", "lab" :jupyterlabをデフォルトで起動させるコマンド。 # "--ip=0.0.0.0" :ローカルでjupyterlabを使うときに必要なコマンド # "--LabApp.token=''" :本来ならjupyterlabを起動させた際にパスワードを入れる必要があるがこう書くことでそれを防ぐ CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root", "--LabApp.token=''"] Dockerfileを用いて、"docker image"を作成する terminal username@MacBook-Pro ~ % cd <Dockerfileを保存した場所> # Dockerfileがあるかどうかを確認する username@MacBook-Pro docker_file % ls >>> Dockerfile # "docker build"を使って構築する(" . " はカレントディレクトリを指すので忘れずに) username@MacBook-Pro docker_file % docker build --platform linux/amd64 . 上記と同じコマンドを入力すれば、docker imageを作成できる。 【重要】M1Macを使用している方は、必ず「--platform linux/amd64」を付けて入力する 付けないとエラーになる ターミナルでDockerfileを起動させる terminal # "docker iamges" を使い、起動したい "docker image" があるかどうかを確認する username@MacBook-Pro ~ % docker iamges >>> REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> dge767nb2v62h 2 days ago 3.66GB # "docker run" を使い "docker image" を起動させる # "-p 8888:8888" はポートを設定するためのオプションなので必須。もし以前に8888を使用したことがあるのであれば、任意のもの(-p 1234:8888)を設定する。 username@MacBook-Pro ~ % docker run -p 8888:8888 dge767nb2v62h 起動させると勝手にJupyterLabが起動するので、Googleで「localhost:8888」と検索するとJupyterlabに入ることができる。入れることを確認できたら、完了。 さらにライブラリを追加したいとき 先ほど作成したDockerfileに以下のコマンドと追加したいライブラリを入力すればいい。追記する場所は、CMDの上あたりでいい。 RUN pip install --upgrade pip RUN pip install <ライブラリの名前> 【補足】AWSでdockerを使用する ここのセクションではAWSにdockerをインストールして、自分のPCにマウントさせることで、自分のPCのメモリなどを使わずデータ分析を行う方法を紹介する。あらかじめAWSアカウント作成後、AWSインスタンスを作成しておくこと! 詳しくは、こちら( https://aws.amazon.com/jp/register-flow/)
- 投稿日:2021-05-09T12:17:29+09:00
おうちにLambdaが欲しい!
はじめて投稿します、はるかなぎと申します。最近になり本格的にAWSを触り始めたいわばにわか勢です。 AWS Lambdaってなあに? AWS Lambdaは、サーバレス型と呼ばれるサービスのひとつで(利用者が)サーバを用意せずに、プログラムを実行できるサービスです。Faas(Function as a Service)と呼ばれる種類のサービスと説明されることもあります。 詳しい内容は、AWS公式の紹介ページを見た方が早いと思います。 AWS Lambda(イベント発生時にコードを実行)| AWS ところで、ローカルで動くの? この手のものを見ると、自宅に環境が欲しくなりますね。調べたところ、AWS SAM CLIというローカルでテストを行うツールがあるようです。 お試し用環境を用意します 早速遊んでみようと、以下のお試し用環境を用意しました。 OS:Amazon Linux 2(KVM用イメージ) ここに、SAM CLIとDockerをインストールしておきます。その他必要なツール(Git等)も一緒にインストールしておきます。(インストール方法は割愛します) 早速ためしてみる SAM CLIで作成したプロジェクトは以下のコマンドでローカル実行することが可能です。実行には、Dockerがインストールされている必要があります。(プロジェクトの作成については割愛します) $ sam local invoke Invoking app.lambda_handler (python3.7) Image was not found. Building image...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0. Mounting /home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container START RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739 Version: $LATEST END RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739 REPORT RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739 Init Duration: 0.18 ms Duration: 93.27 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 128 MB {"statusCode": 200, "body": "{\"message\": \"hello world\"}"} sam local invokeで実行すると、上記の通り作成したLambda関数が実行されます。まぁここまでは普通の話です。SAM CLIでの実行にDockerが必要と書かれていたので、どのようなコンテナが作られるのか調べようと、意気揚々とコンテナ一覧を見てやろうとしたところ・・・ $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES あれ?何もないぞ?? 試しにイメージ一覧を出してみると、それらしきイメージが存在します。 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE amazon/aws-sam-cli-emulation-image-python3.7 rapid-1.22.0 39513e8ac96d 3 minutes ago 908MB amazon/aws-sam-cli-emulation-image-python3.7 latest c8f4d7381293 About an hour ago 892MB まさかと思い、sam local invokeを叩いた直後にdocker psを連発してみたところ・・・ $ docker ps --no-trunc=true CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0ab3d3c601864b1b539dddd7ac27c0972b09ceef137ed65c1acf9053e1884cba amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 "/var/rapid/aws-lambda-rie --log-level error" 3 seconds ago Up Less than a second 127.0.0.1:7706->8080/tcp busy_wiles お、出た出た。どうやら、SAM CLIで実行すると、Lambdaの実行環境を含んだDockerコンテナが作成され、実行後に削除するという動きをするようです。 イメージを調べてみよう 上記の手順で表示されたイメージは、Docker Hubにあるようです。 amazon/aws-sam-cli-build-image-python3.7 とりあえず作成されているイメージを消してから、dockerコマンドでpullしてみます。 $ docker pull amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 Error response from daemon: manifest for amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 not found: manifest unknown: manifest unknown ん?イメージが存在しない?試しにタグを指定せずにpullします。 $ docker pull amazon/aws-sam-cli-emulation-image-python3.7 Using default tag: latest latest: Pulling from amazon/aws-sam-cli-emulation-image-python3.7 df5bcad6d15c: Pull complete 1c6619c430f8: Pull complete 6577ccaf68c7: Pull complete 649bca99560c: Pull complete Digest: sha256:5358339925e231e94c2c4e0d917af54cadb312625a30df28cda271c5b844d9c9 Status: Downloaded newer image for amazon/aws-sam-cli-emulation-image-python3.7:latest docker.io/amazon/aws-sam-cli-emulation-image-python3.7:latest 無事にpullできました。 先ほどイメージを表示したときにもlatestのものが表示されていたので、どうやらSAM CLIでの実行時にlatestのイメージから作成しているようです。 ということは、イメージの差分を見れば、どのようなイメージかが分かります。もう一度SAM CLIで実行し、イメージを作成、historyを比較してみましょう。 まずはlatest $ docker history amazon/aws-sam-cli-emulation-image-python3.7:latest --no-trunc=true IMAGE CREATED CREATED BY SIZE COMMENT sha256:c8f4d7381293badf23098d75b891c50a6682a3146ed5c90a889f4685f0f90017 2 hours ago CMD [ "/bin/bash" ] 0B <missing> 2 hours ago ENV LAMBDA_RUNTIME_DIR=/var/runtime 0B <missing> 2 hours ago ENV LAMBDA_TASK_ROOT=/var/task 0B <missing> 2 hours ago ENV LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib 0B <missing> 2 hours ago ENV PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin 0B <missing> 2 hours ago ENV TZ=:/etc/localtime 0B <missing> 2 hours ago ENV LANG=en_US.UTF-8 0B <missing> 2 hours ago WORKDIR /var/task 0B <missing> 2 hours ago ADD file:649bca99560c52ca2195dc8410dbee9e1634faa448acfee4696f74db0651773f / 66.4MB <missing> 2 hours ago ADD file:6577ccaf68c7a9a42e7b1a8bbfa93959abc28b47888855eba289c032685c6770 / 173MB <missing> 2 hours ago ADD file:1c6619c430f8d56651115043ea1cd3e6d293434dc774f21cc087e86aebf6e1d4 / 424kB <missing> 2 hours ago ADD file:32665f54d46653b07d35bfa9cdd4baf9b1144d6824516a05218124afc01246f3 / 652MB <missing> 2 hours ago ARCHITECTURE amd64 0B 0B 次にrapid-1.22.0 ]$ docker history amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 --no-trunc=true IMAGE CREATED CREATED BY SIZE COMMENT sha256:b42538372e40f0627b62b40313690f2561f7bba02683c066e4221ea32dd2072b 5 minutes ago /bin/sh -c chmod +x /var/rapid/aws-lambda-rie 8.16MB sha256:cddd62fd80bd20c647cd6d8cc12ff1bfb822da1706e3e7eb9c44c705c559a55f 5 minutes ago /bin/sh -c #(nop) ADD dir:bf074fbf6e9076431dc41d00943644a0df7bd2853140615db6ae0130fd5c91f8 in /var/rapid 8.16MB sha256:c8f4d7381293badf23098d75b891c50a6682a3146ed5c90a889f4685f0f90017 2 hours ago CMD [ "/bin/bash" ] 0B <missing> 2 hours ago ENV LAMBDA_RUNTIME_DIR=/var/runtime 0B <missing> 2 hours ago ENV LAMBDA_TASK_ROOT=/var/task 0B <missing> 2 hours ago ENV LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib 0B <missing> 2 hours ago ENV PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin 0B <missing> 2 hours ago ENV TZ=:/etc/localtime 0B <missing> 2 hours ago ENV LANG=en_US.UTF-8 0B <missing> 2 hours ago WORKDIR /var/task 0B <missing> 2 hours ago ADD file:649bca99560c52ca2195dc8410dbee9e1634faa448acfee4696f74db0651773f / 66.4MB <missing> 2 hours ago ADD file:6577ccaf68c7a9a42e7b1a8bbfa93959abc28b47888855eba289c032685c6770 / 173MB <missing> 2 hours ago ADD file:1c6619c430f8d56651115043ea1cd3e6d293434dc774f21cc087e86aebf6e1d4 / 424kB <missing> 2 hours ago ADD file:32665f54d46653b07d35bfa9cdd4baf9b1144d6824516a05218124afc01246f3 / 652MB <missing> 2 hours ago ARCHITECTURE amd64 0B /var/rapid/配下にファイルを追加し、/var/rapid/aws-lambda-rieに実行権限を付与しているという違いが見つかりました。この/var/rapid/aws-lambda-rieの有無がこの2つのイメージの違いのようです。 aws-lambda-rieってなあに? ではこのaws-lambda-rieって何者なのか調べたところ、AWS Lambda Runtime Interface Emulatorと呼ばれるもので、名前の通りLambda実行環境のエミュレータのようです。 ここで、先ほどのコンテナ一覧の結果を見てみましょう。COMMANDの箇所を見ると「/var/rapid/aws-lambda-rie --log-level error」とあるので、まさにこいつをコンテナ作成時に実行しています。 コンテナの中身はなんだろな では、次にコンテナを調べていきます。 先ほどの情報だけだと足りないので、docker inspectコマンドで中身を見てみます。 しかし、実行時にコンテナが作成され、実行後に削除される関係上、まともにコマンドを叩いていては間に合わないので、簡単なスクリプトを作って取得します。なお、目的のコンテナの情報さえ取れれば良いということで複数コンテナが動いている状況はまったく考慮していませんのでご注意ください。 #!/bin/bash CONTAINER_ID=`docker ps -q` echo ${CONTAINER_ID} docker inspect ${CONTAINER_ID} コンテナが起動している間にこのスクリプトを実行すると以下のような情報が得られます。 [ { "Id": "85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829", "Created": "2021-04-26T13:20:45.676396302Z", "Path": "/var/rapid/aws-lambda-rie", "Args": [ "--log-level", "error" ], "State": { "Status": "removing", "Running": false, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": true, "Pid": 0, "ExitCode": 137, "Error": "", "StartedAt": "2021-04-26T13:20:47.643574462Z", "FinishedAt": "2021-04-26T13:20:49.361733871Z" }, "Image": "sha256:b42538372e40f0627b62b40313690f2561f7bba02683c066e4221ea32dd2072b", "ResolvConfPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/resolv.conf", "HostnamePath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/hostname", "HostsPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/hosts", "LogPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829-json.log", "Name": "/elated_archimedes", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": [ "/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction:/var/task:ro,delegated" ], "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": { "8080/tcp": [ { "HostIp": "127.0.0.1", "HostPort": "5018" } ] }, "RestartPolicy": { "Name": "", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "Capabilities": null, "Dns": null, "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": 0, "Memory": 134217728, "NanoCpus": 0, "CgroupParent": "", "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, "DeviceRequests": null, "KernelMemory": 0, "KernelMemoryTCP": 0, "MemoryReservation": 0, "MemorySwap": 268435456, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": null, "Ulimits": [ { "Name": "nofile", "Hard": 4096, "Soft": 1024 } ], "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8-init/diff:/var/lib/docker/overlay2/3f3546128854b10663811112acc8423f84abcc1f47b3073172b55bdb3768a7af/diff:/var/lib/docker/overlay2/bcfc11b7e7c587d3a01e09c4c843a3525635ec782635bdc3e707cb56d0d5733b/diff:/var/lib/docker/overlay2/a10c8af58d6fa1f634045400e21b7f6dbbca281ba68a0ab9b5cf23ecaae7c9a7/diff:/var/lib/docker/overlay2/2cdd94e4f72dc4af42a1d5f1d25d8716ed0d7330261c5489ce847882c872d577/diff:/var/lib/docker/overlay2/a6630cafd3c07e2e8a198af012f75d3f035fc4e8ad2a69d5a2edc9d0da7c529c/diff:/var/lib/docker/overlay2/6f9c1a2e3d92bfb822c9f028fe7d98f964cd19a89b063f4082639dba4d1563ce/diff", "MergedDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/merged", "UpperDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/diff", "WorkDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/work" }, "Name": "overlay2" }, "Mounts": [ { "Type": "bind", "Source": "/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction", "Destination": "/var/task", "Mode": "ro,delegated", "RW": false, "Propagation": "rprivate" } ], "Config": { "Hostname": "85faef4d31c7", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "ExposedPorts": { "8080/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "AWS_SAM_LOCAL=true", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128", "AWS_LAMBDA_FUNCTION_TIMEOUT=3", "AWS_LAMBDA_FUNCTION_HANDLER=app.lambda_handler", "AWS_LAMBDA_FUNCTION_NAME=HelloWorldFunction", "AWS_LAMBDA_FUNCTION_VERSION=$LATEST", "AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/HelloWorldFunction", "AWS_LAMBDA_LOG_STREAM_NAME=$LATEST", "AWS_REGION=us-east-1", "AWS_DEFAULT_REGION=us-east-1", "AWS_ACCESS_KEY_ID=defaultkey", "AWS_SECRET_ACCESS_KEY=defaultsecret", "AWS_ACCOUNT_ID=123456789012", "LANG=en_US.UTF-8", "TZ=:/etc/localtime", "PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "LAMBDA_TASK_ROOT=/var/task", "LAMBDA_RUNTIME_DIR=/var/runtime" ], "Cmd": [], "Image": "amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0", "Volumes": { "/var/task": {} }, "WorkingDir": "/var/task", "Entrypoint": [ "/var/rapid/aws-lambda-rie", "--log-level", "error" ], "OnBuild": null, "Labels": {} }, "NetworkSettings": { "Bridge": "", "SandboxID": "1123e52e745924dc1fce7584d2985878104283b8ea348c9cae5c6466c4dfc591", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": {}, "SandboxKey": "/var/run/docker/netns/1123e52e7459", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "", "Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "", "IPPrefixLen": 0, "IPv6Gateway": "", "MacAddress": "", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "bb6cb306d6052a81de21c664211c4eafa397dca82b8b690a60d8c7e870413a69", "EndpointID": "", "Gateway": "", "IPAddress": "", "IPPrefixLen": 0, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "", "DriverOpts": null } } } } ] 長ったらしいJSONですが、すべてを見る必要はありません。必要なところだけ見ていきます。 コマンド 「/var/rapid/aws-lambda-rie --log-level error」であることがここでも確認できます。 "Path": "/var/rapid/aws-lambda-rie", "Args": [ "--log-level", "error" ] ポートバインディング ホストの127.0.0.1:5018にバインドしているようです。ポートはランダムになるみたいなので、実際に動かすときは任意のポートにできると思います。IPが127.0.0.1なので、この設定では外部からアクセスできません。 "PortBindings": { "8080/tcp": [ { "HostIp": "127.0.0.1", "HostPort": "5018" } ] } メモリ容量 後述の環境変数でも指定されていますが、128MBが割り当てられているようです。 "Memory": 134217728 環境変数 色々設定されていますが、先ほど確認したコンテナのhistoryの情報からLANGから下はイメージ側で設定されていることがすでに判明していますので、コンテナを作成する際は「AWS」から始まるものを設定すればよさそうです。 "Env": [ "AWS_SAM_LOCAL=true", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128", "AWS_LAMBDA_FUNCTION_TIMEOUT=3", "AWS_LAMBDA_FUNCTION_HANDLER=app.lambda_handler", "AWS_LAMBDA_FUNCTION_NAME=HelloWorldFunction", "AWS_LAMBDA_FUNCTION_VERSION=$LATEST", "AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/HelloWorldFunction", "AWS_LAMBDA_LOG_STREAM_NAME=$LATEST", "AWS_REGION=us-east-1", "AWS_DEFAULT_REGION=us-east-1", "AWS_ACCESS_KEY_ID=defaultkey", "AWS_SECRET_ACCESS_KEY=defaultsecret", "AWS_ACCOUNT_ID=123456789012", "LANG=en_US.UTF-8", "TZ=:/etc/localtime", "PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "LAMBDA_TASK_ROOT=/var/task", "LAMBDA_RUNTIME_DIR=/var/runtime" ] 環境変数 値(例) 説明 AWS_SAM_LOCAL true SAM LOCALで実行しているかを示す模様 AWS_LAMBDA_FUNCTION_MEMORY_SIZE 128 メモリサイズ(MB) AWS_LAMBDA_FUNCTION_TIMEOUT 3 関数実行タイムアウト時間 AWS_LAMBDA_FUNCTION_HANDLER app.lambda_handler ハンドラ(後述) AWS_LAMBDA_FUNCTION_NAME HelloWorldFunction Lambda関数名 AWS_LAMBDA_FUNCTION_VERSION $LATEST Lambda関数のバージョン AWS_LAMBDA_LOG_GROUP_NAME aws/lambda/HelloWorldFunction ロググループ名 AWS_LAMBDA_LOG_STREAM_NAME $LATEST ログストリーム名 AWS_REGION us-east-1 リージョン AWS_DEFAULT_REGION us-east-1 デフォルトリージョン AWS_ACCESS_KEY_ID defaultkey IAMアクセスキー AWS_SECRET_ACCESS_KEY defaultsecret IAMシークレットキー AWS_ACCOUNT_ID 123456789012 AWSアカウントID マウント情報 SourceにSAM CLIでビルドしたLambda関数のディレクトリが読み取り専用で指定されています。つまり、コンテナと作成したコードを紐づける、一番重要な部分になります。 "Mounts": [ { "Type": "bind", "Source": "/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction", "Destination": "/var/task", "Mode": "ro,delegated", "RW": false, "Propagation": "rprivate" } ], Sourceに指定されているディレクトリを確認すると、以下のような結果が得られます。 $ ls -l /home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction 合計 16 -rw-rw-r-- 1 izayoiwind izayoiwind 0 4月 17 08:23 __init__.py -rw-rw-r-- 1 izayoiwind izayoiwind 1151 4月 17 08:23 app.py drwxrwxr-x 2 izayoiwind izayoiwind 77 4月 17 08:23 certifi drwxrwxr-x 2 izayoiwind izayoiwind 85 4月 17 08:23 certifi-2020.12.5.dist-info drwxrwxr-x 4 izayoiwind izayoiwind 4096 4月 17 08:23 chardet drwxrwxr-x 2 izayoiwind izayoiwind 109 4月 17 08:23 chardet-4.0.0.dist-info drwxrwxr-x 2 izayoiwind izayoiwind 155 4月 17 08:23 idna drwxrwxr-x 2 izayoiwind izayoiwind 89 4月 17 08:23 idna-2.10.dist-info drwxrwxr-x 2 izayoiwind izayoiwind 4096 4月 17 08:23 requests drwxrwxr-x 2 izayoiwind izayoiwind 85 4月 17 08:23 requests-2.25.1.dist-info -rw-rw-r-- 1 izayoiwind izayoiwind 8 4月 17 08:23 requirements.txt drwxrwxr-x 5 izayoiwind izayoiwind 272 4月 17 08:23 urllib3 drwxrwxr-x 2 izayoiwind izayoiwind 133 4月 17 08:23 urllib3-1.26.4.dist-info app.pyの内容は以下の通りです。 app.py import json # import requests def lambda_handler(event, context): """Sample pure Lambda function Parameters ---------- event: dict, required API Gateway Lambda Proxy Input Format Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format context: object, required Lambda Context runtime methods and attributes Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html Returns ------ API Gateway Lambda Proxy Output Format: dict Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html """ # try: # ip = requests.get("http://checkip.amazonaws.com/") # except requests.RequestException as e: # # Send some context about this error to Lambda Logs # print(e) # raise e return { "statusCode": 200, "body": json.dumps({ "message": "hello world", # "location": ip.text.replace("\n", "") }), } 環境変数のハンドラの指定について では、ここで環境変数のハンドラの指定を見てみましょう。以下のように指定されています。 app.lambda_handler これを踏まえて、上記のapp.pyのコードを見ると、以下のように指定するということが分かります。 <拡張子を除いたソースファイル>.<関数名> よろしい、ならば手動で動かすまでだ ここまで得た情報で、実際にSAM CLIを使わずに動かすことができます。 せっかくなので、SAM CLIで作ったものではなく、独自で作ってみます。以下のコードをi_want_five_quadrillion_yen.pyという名前で保存します。(エラー処理等は特に考えてません、さらに筆者はPythonに関しては初心者レベルですので悪しからず) # coding: utf-8 import json def lambda_func(event, context): output = '{}兆円欲しい!'.format(event['input']) return { 'output': output, } 保存先は/home/izayoiwind/i_want_five_quadrillion_yen/としています。 それでは、コンテナを起動します。 $ sudo docker run -d -m "128M" \ -e AWS_SAM_LOCAL=true \ -e AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128 \ -e AWS_LAMBDA_FUNCTION_TIMEOUT=3 \ -e AWS_LAMBDA_FUNCTION_HANDLER=i_want_five_quadrillion_yen.lambda_func \ -e AWS_LAMBDA_FUNCTION_NAME=IWantFiveQuadrillionYen \ -e AWS_LAMBDA_FUNCTION_VERSION=$LATEST \ -e AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/IWantFiveQuadrillionYen \ -e AWS_LAMBDA_LOG_STREAM_NAME=$LATEST \ -e AWS_REGION=us-east-1 \ -e AWS_DEFAULT_REGION=us-east-1 \ -e AWS_ACCESS_KEY_ID=defaultkey \ -e AWS_SECRET_ACCESS_KEY=defaultsecret \ -e AWS_ACCOUNT_ID=123456789012 \ -p 8080:8080 \ -v /home/izayoiwind/i_want_five_quadrillion_yen:/var/task:ro,delegated \ amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 \ /var/rapid/aws-lambda-rie --log-level error 起動後、curlで以下のURLを叩くと、Lambda関数が実行されます。Pythonの場合、マルチバイト文字を入れるとUnicodeエスケープシーケンスで返されるようなので、応答結果にちょっと細工をいれています。 $ curl -XPOST "http://localhost:8080/2015-03-31/functions/function/invocations" -s -d '{"input": "5000"}' | python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")' {"output": "5000兆円欲しい!"} 【おまけ】作成したコンテナの関数をAWS CLIから叩いてみる ところで、先ほど出てきた以下のURLですが、このURLはAWS CLIでLambda関数を叩くときのURLと同様です。 なので、AWS CLIからも叩くことが可能です。 以下のコマンドで叩くことができます。(関係ないけどAmazon Linux 2イメージに含まれるAWS CLIは1.x系のようです) $ aws --endpoint-url http://localhost:8080 lambda invoke --function-name function --payload '{"input":"5000"}' ./test.txt { "StatusCode": 200 } $ cat ./test.txt | python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")' {"output": "5000兆円欲しい!"} AWS CLI 2.x系の場合はpayloadにbase64エンコードした文字列を指定します。AWS CLI 2.x系を入れていた環境がPython 3系だったため、Unicodeエスケープ関連の処理を少し変えています。 $ echo {\"input\":\"5000\"} | base64 eyJpbnB1dCI6IjUwMDAifQo= $ aws --endpoint-url http://amzn.izayoiwind.net:8080 lambda invoke --function-name function --payload eyJpbnB1dCI6IjUwMDAifQo= ./test.txt { "StatusCode": 200 } $ cat test.txt | python -c 'from sys import stdin; print(stdin.readline().encode("utf-8").decode("unicode-escape"));' {"output": "5000兆円欲しい!"} 注意点として、本家AWS LambdaをCLI経由で呼び出した場合、レスポンスにX-Amz-Function-Errorヘッダが含まれるため、以下のようにFunctionErrorが通知されますが、エミュレータでの実行の場合、実行に失敗してもレスポンスにX-Amz-Function-Errorヘッダが含まれないようで、ステータスコード以外の情報は一切通知されません。 $ aws lambda invoke --function-name i_want_five_quadrillio n_yen ./test.txt { "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST", "StatusCode": 200 }
- 投稿日:2021-05-09T11:20:15+09:00
パスワード認証付きdocker-registryを導入する
業務でdocker-registryを導入する機会があり、復習のため再度デプロイします。 環境はAWS/EC2を使用しました。 docker-registryとは何か コンテナイメージを格納する場所です。docker-registry自体もコンテナイメージとして提供されています。 環境 【クライアント】 $ cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) $ docker --version Docker version 20.10.3, build 48d30b5 【サーバ】 $ uname -a Linux ip-192-168-100-209.ap-northeast-1.compute.internal 4.14.231-173.360.amzn2.x86_64 #1 SMP Mon Apr 19 23:20:22 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux $ docker --version Docker version 20.10.4, build d3cb89e ※ドキュメントによるとdocker-registryが稼働するホストのdockerバージョンは1.6.0以上が望ましいと記載があります。試す場合はdockerのバージョンをあらかじめ確認しましょう。 やりたいこと docker-registryのデプロイ docker-registryにパスワードを設定する docker-registryのアクセスログを出力する データの永続化を行う 1. docker-registryのデプロイ イメージのpull 使用するのはdocker公式に記載のあるregistryです。cliだと以下で確認できます 【サーバ作業】 $ docker search registry --filter is-official=true --no-trunc NAME DESCRIPTION STARS OFFICIAL AUTOMATED registry The Docker Registry 2.0 implementation for storing and distributing Docker images 3274 [OK] # --filter is-official=trueで公式イメージのみを出力 # --no-truncで出力を省略しない デプロイ 以下でデプロイします。registryが使用するポートは5000であるため、忘れずに指定します。 $ docker run -d -p 5000:5000 --name registry registry:2 ... Status: Downloaded newer image for registry:2 9c35e33e6b6cf5035731c2172b0b0ecfcd20e1ac17c5e598675f7fcaaedba035 # -d デタッチ。バックグラウンドで動作させる 最後にイメージIDが出てきたら成功です。確認してみましょう。 $ docker images registry:2 REPOSITORY TAG IMAGE ID CREATED SIZE registry 2 1fd8e1b0bb7e 2 weeks ago 26.2MB $ docker container ps --no-trunc CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9c35e33e6b6cf5035731c2172b0b0ecfcd20e1ac17c5e598675f7fcaaedba035 registry:2 "/entrypoint.sh /etc/docker/registry/config.yml" 2 minutes ago Up 2 minutes 0.0.0.0:5000->5000/tcp registry 先ほどのログと同じImageIDが出てきました。問題なさそうです。 nginxコンテナをデプロイ 問題なくpush,pullできるかを確認するため、例としてnginx公式イメージからコンテナをたてます。 【クライアント作業】 ### イメージ確認 $ docker search nginx --filter is-official=true NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Official build of Nginx. 14814 [OK] ### nginxコンテナをデプロイ $ docker run -i -d -p 8080:80 --name test-nginx nginx:latest Status: Downloaded newer image for nginx:latest 21e118a574751848dd2b2c1a28d20852d5348004c9909b5539a8cb32f1d7d9e0 ### 確認 $ docker container ps --no-trunc | grep nginx 21e118a574751848dd2b2c1a28d20852d5348004c9909b5539a8cb32f1d7d9e0 nginx:latest "/docker-entrypoint.sh nginx -g 'daemon off;'" About a minute ago Up About a minute 0.0.0.0:8080->80/tcp test-nginx $ docker images nginx:latest REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 62d49f9bab67 3 weeks ago 133MB ### 疎通確認 $ curl localhost:8080 -I HTTP/1.1 200 OK Server: nginx/1.19.10 Date: Wed, 05 May 2021 06:02:33 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 13 Apr 2021 15:13:59 GMT Connection: keep-alive ETag: "6075b537-264" Accept-Ranges: bytes 問題なさそうですね。このイメージをpushしてみます。デプロイしたコンテナはイメージ削除をするため削除しましょう $ docker rm -f test-nginx test-nginx registryへのpush,pull テスト用と識別するためにタグを付けます。 タグのフォーマットは以下となりますので、環境に合わせて名づけましょう。今回はホスト名にEC2のpublic DNSをつけています ### リポジトリで管理する場合 <ホスト名>:<ポート番号>/<リポジトリ>/<イメージ名>:<タグ> ### リポジトリで管理しない場合 <ホスト名>:<ポート番号>/<イメージ名>:<タグ> フォーマットにしたがってタグを付けます $ docker image tag nginx ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx:test $ docker images | grep nginx nginx latest 62d49f9bab67 3 weeks ago 133MB ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx test 62d49f9bab67 3 weeks ago 133MB pushします $ docker push ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx:test The push refers to repository [ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx] Get https://ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/v2/: http: server gave HTTP response to HTTPS client エラーになりました。 https接続しなければ行けないところでhttp接続をしていたためにエラーが出た様です。 証明書を作成する必要があるのですが、今回はhttpで接続できるようにします。 httpsで接続する方法は別の機会に投稿したいと思っています。 クライアントにdaemon.jsonを追加 ドキュメントに記載の方法で行います。安全な方法ではないためご承知おきください。pull,pushするサーバで以下を実施します。 $ vi /etc/docker/daemon.json $ cat /etc/docker/daemon.json { "insecure-registries" : ["ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000"] } ### 反映のため、サービス再起動 $ sudo systemctl restart docker 再度pushします $ docker push ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx:test The push refers to repository [ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx] 64ee8c6d0de0: Layer already exists 974e9faf62f1: Layer already exists 15aac1be5f02: Layer already exists 23c959acc3d0: Layer already exists 4dc529e519c4: Layer already exists 7e718b9c0c8c: Layer already exists test: digest: sha256:42bba58a1c5a6e2039af02302ba06ee66c446e9547cbfb0da33f4267638cdb53 size: 1570 できました! 手元のイメージを削除し、↑でpushしたイメージが使用できるか試しましょう $ docker rmi nginx:latest $ docker rmi ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx:test $ docker images | grep nginx $ ### imageのpull $ docker pull ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx:test test: Pulling from nginx f7ec5a41d630: Pull complete aa1efa14b3bf: Pull complete b78b95af9b17: Pull complete c7d6bca2b8dc: Pull complete cf16cd8e71e0: Pull complete 0241c68333ef: Pull complete Digest: sha256:42bba58a1c5a6e2039af02302ba06ee66c446e9547cbfb0da33f4267638cdb53 Status: Downloaded newer image for ec2-52-197-137-171.ap-northeast-1.com ### nginxコンテナの起動、確認 $ docker run -i -d -p 8080:80 --name test-nginx-again ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx:test af5f53d7387c66d0dc42e05b2231c03cbf0dd599b2f91ddd2dc769d3770c0180 $ curl localhost:8080 -I HTTP/1.1 200 OK Server: nginx/1.19.10 Date: Wed, 05 May 2021 06:33:06 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 13 Apr 2021 15:13:59 GMT Connection: keep-alive ETag: "6075b537-264" Accept-Ranges: bytes 無事pushできました! 2. docker-registryにパスワードを設定する デフォルトではdocker-registryにパスワードは設定されていませんが、以下の方法で設定可能です。今回はhtpasswdを利用します silly token htpasswd またこういった設定をregistryに対して行うには以下の2つがあげられます 公式イメージに環境変数を設定する 設定ファイルを適用させる 今回は後者を使いたいと思います。 設定ファイルを作る 設定ファイルを作り、docker-registryに適用させます。ドキュメントの例から必要そうな設定をコピペしました。 【サーバ作業】 ※ EC2を停止したためpublic DNSが変わっていますが、同環境です。 config.yml version: 0.1 auth: htpasswd: realm: basic-realm path: /auth/htpasswd htpasswdファイルが必要なため、ホスト側で作成してコンテナと共有するようにします $ htpasswd -c -b -B test.htpasswd test test Adding password for user test # -c 新規htpasswdファイル作成 # -b コマンドラインからのパスワードを受け取る # -B bcrypt方式を使う。bcryptはハッシュパスワード生成方式の一つ では立ち上げてみましょう 新しいregistryをデプロイ 重複を避けるため、ホストの5001番ポートを使用します ### 立ち上げ docker run -d -p 5001:5000 --restart=always --name registry-htpasswd \ -v `pwd`/config.yml:/etc/docker/registry/config.yml \ -v `pwd`/test.htpasswd:/auth/htpasswd \ registry:2 afe3cad9f424352ba4768aab734f989cabf148b66e887eda2d076a5d8e319968 ### 確認 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES afe3cad9f424 registry:2 "/entrypoint.sh /etc…" 46 seconds ago Restarting (1) 14 seconds ago registry-htpasswd 9c35e33e6b6c registry:2 "/entrypoint.sh /etc…" 7 hours ago Up 41 minutes 0.0.0.0:5000->5000/tcp registry Restartingが出力されました。しばらく待ってもrunningとならないため、調査を実施します。 コンテナのログを見てみる docker logsコマンドで見てみましょう $ docker logs registry-htpasswd configuration error: error parsing /etc/docker/registry/config.yml: No storage configuration provided Usage: registry serve <config> [flags] Flags: -h, --help=false: help for serve Additional help topics: configuration error: error parsing /etc/docker/registry/config.yml: No storage configuration provided Usage: registry serve <config> [flags] Flags: -h, --help=false: help for serve Additional help topics: configuration error: error parsing /etc/docker/registry/config.yml: No storage configuration provided Usage: registry serve <config> [flags] Flags: -h, --help=false: help for serve ... # あとはこれの繰り返し config.ymlのstorage設定が足りていない様です。さらにあたりを付けるために、最初にデプロイしたregistryのconfig.ymlを見てみます config.ymlを見てみる ### 対象確認 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES afe3cad9f424 registry:2 "/entrypoint.sh /etc…" 7 minutes ago Restarting (1) 26 seconds ago registry-htpasswd 9c35e33e6b6c registry:2 "/entrypoint.sh /etc…" 7 hours ago Up 48 minutes 0.0.0.0:5000->5000/tcp registry ### registryの中に入る $ docker exec -it registry sh / # ### config.ymlを見る / # cat /etc/docker/registry/config.yml version: 0.1 log: fields: service: registry storage: cache: blobdescriptor: inmemory filesystem: rootdirectory: /var/lib/registry http: addr: :5000 headers: X-Content-Type-Options: [nosniff] health: storagedriver: enabled: true interval: 10s threshold: 3 ### 抜ける / # exit こちらにもstorage設定がありました。いろいろ設定がありますが、ひとまずstorage設定を入れてみます。 再度設定ファイルを作成する config.yml version: 0.1 storage: cache: # ディスクキャッシュの格納場所。コンテナのメモリ領域を使用する。 blobdescriptor: inmemory filesystem: # ローカルのファイルシステムを使用 rootdirectory: /var/lib/registry # /var/lib/registryにコンテナイメージを格納 auth: htpasswd: realm: basic-realm path: /auth/htpasswd 再デプロイ 再びデプロイしてみます ### restarting状態のコンテナ削除 $ docker rm -f registry-htpasswd registry-htpasswd ### デプロイ $ docker run -d -p 5001:5000 --restart=always --name registry-htpasswd \ > -v `pwd`/config.yml:/etc/docker/registry/config.yml \ > -v `pwd`/test.htpasswd:/auth/htpasswd \ > registry:2 2d1b34cc45c484aab15ac2abff4f75c16d3d4bc42c8ec25fc2aa39272da30a43 ### 確認 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2d1b34cc45c4 registry:2 "/entrypoint.sh /etc…" 3 seconds ago Up 2 seconds 0.0.0.0:5001->5000/tcp registry-htpasswd 9c35e33e6b6c registry:2 "/entrypoint.sh /etc…" 7 hours ago Up About an hour 0.0.0.0:5000->5000/tcp registry 今度はうまく行ってそうです。ログイン、push,pullを試してみましょう。 認証の確認をする まずパスワードを使用しないパターンを試します 【クライアント作業】 ### 5001番ポートもhttp通信を許可する $ sudo vi /etc/docker/daemon.json $ cat /etc/docker/daemon.json { "insecure-registries" : [ "ec2-3-113-20-153.ap-northeast-1.compute.amazonaws.com:5000", "ec2-3-113-20-153.ap-northeast-1.compute.amazonaws.com:5001" ] } $ sudo systemctl restart docker ### タグを5001番ポートに変更 $ docker image tag ec2-52-197-137-171.ap-northeast-1.compute.amazonaws.com:5000/nginx:test ec2-3-113-20-153.ap-northeast-1.compute.amazonaws.com:5001/nginx:test ### ログイン $ docker login ec2-3-113-20-153.ap-northeast-1.compute.amazonaws.com:5001 Username: test Password: Error response from daemon: Get http://ec2-3-113-20-153.ap-northeast-1.compute.amazonaws.com:5001/v2/: dial tcp 3.113.20.153:5001: connect: connection refused どういうわけか失敗。また調査をします。 Registry APIを通して疎通確認をする docker-registryはhttpメソッドを使って情報を取得できます(ここ)。GETでレジストリ一覧を確認し、疎通確認をしてみます。 ### 5000番ポートのregistryの場合 $ curl http://ec2-3-113-20-153.ap-northeast-1.compute.amazonaws.com:5000/v2/_catalog {"repositories":["nginx"]} ### 5001番ポートのregistryの場合 $ curl http://ec2-3-113-20-153.ap-northeast-1.compute.amazonaws.com:5001/v2/_catalog curl: (7) Failed connect to ec2-3-113-20-153.ap-northeast-1.compute.amazonaws.com:5001; 接続を拒否されました 5000番の方はAPIと通信可能なため、daemonファイルは間違っていなさそうです。それではconfig.ymlに足りない内容があるのでしょうか config.ymlを編集 ドキュメントを確認したところ、httpオプションのaddrパラメータは設定が必須であったため、追記します。 【サーバ作業】 config.yml version: 0.1 storage: cache: blobdescriptor: inmemory filesystem: rootdirectory: /var/lib/registry http: addr: :5000 # 5000番でコネクションを受け付ける auth: htpasswd: realm: basic-realm path: /auth/htpasswd 接続 再度接続してみます。 【クライアント作業】 $ docker login ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5001 Username: test Password: .... Login Succeeded うまくいきました。pushしてみます $ push ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5001/alpine:test The push refers to repository [ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5001/alpine] b2d5eeeaba3a: Pushed test: digest: sha256:def822f9851ca422481ec6fee59a9966f12b351c62ccb9aca841526ffaa9f748 size: 528 問題なくできました! ちなみに認証情報は~/.docker/config.jsonにdocker login時に保存されています。その認証情報を消してpullすると以下の様に失敗します。 $ cat ~/.docker/config.json { "auths": { "ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5001": { "auth": "dGVzdDp0ZXN0" } } } $ rm -f ~/.docker/config.json $ docker pull ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5001/alpine:test Error response from daemon: Head http://ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5001/v2/alpine/manifests/test: no basic auth credentials ログインする前に上記のファイルを用意しておくとdocker loginを省略できます。 3. docker-registryのアクセスログを出力する 開発、運用ではログ確認は必須なので出力方法を確認します。先ほどのconfig.ymlに適用します。 【サーバ作業】 config.yml version: 0.1 log: accesslog: disabled: false # アクセスログを有効にするか。falseで有効にする level: warn # ログレベル。error,warn,info,debugより選択 formatter: text # 出力方式。text,json,logstashより選択 fields: environment: test # ログにこのkey:valueが記載される storage: cache: blobdescriptor: inmemory filesystem: rootdirectory: /var/lib/registry http: addr: :5000 auth: htpasswd: realm: basic-realm path: /auth/htpasswd それでは同じくコンテナを起動します。5002番ポートに新しく立ち上げました。 $ docker run -d -p 5002:5000 --restart=always --name registry-accesslog \ > -v `pwd`/config.yml:/etc/docker/registry/config.yml \ > -v `pwd`/test.htpasswd:/auth/htpasswd \ > registry:2 da913907d63db081a4187e82eef2aaca50fe4064bbcb513792979f2e1aea76ff $ docker ps | grep 5002 da913907d63d registry:2 "/entrypoint.sh /etc…" 9 seconds ago Up 8 seconds 0.0.0.0:5002->5000/tcp registry-accesslog ログインからのpushでアクセスログを確かめてみましょう 【クライアント作業】 $ docker login ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5002 Username: test Password: ... Login Succeeded $ docker push ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5002/alpine:test The push refers to repository [ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5002/alpine] b2d5eeeaba3a: Pushed test: digest: sha256:def822f9851ca422481ec6fee59a9966f12b351c62ccb9aca841526ffaa9f748 size: 528 ドキュメントによるとアクセスログは標準出力に出るそうです。pushした時のログをdocker logsで見てみましょう 【サーバ作業】 $ docker logs registry-accesslog ... time="2021-05-08T13:42:54.239202664Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." environment=test go.version=go1.11.2 instance.id=024cd523-5f2b-4808-9437-d0cbe5a6d11a version=v2.7.1 ... xxx.xxx.xxx.xxx - - [08/May/2021:13:45:55 +0000] "GET /v2/ HTTP/1.1" 401 87 "" "docker/20.10.3 go/go1.13.15 git-commit/46229ca kernel/3.10.0-1160.15.2.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/20.10.3 \\(linux\\))" いろいろ省略していますが、最初の例ではenvironment:testが表示され、二つ目の例ではアクセスログが出力されています。 4. データの永続化を行う イメージのpushを行いましたが、コンテナを削除するとそのデータは消えてしまいます。データを残すためにはコンテナとホストでデータ(ディレクトリ)を共有する必要があります。 docker runを行うタイミングでディレクトリ共有してみます。 【サーバ作業】 $ docker run -d -p 5003:5000 --restart=always --name registry-volume \ > -v `pwd`/config.yml:/etc/docker/registry/config.yml \ > -v `pwd`/test.htpasswd:/auth/htpasswd \ > -v `pwd`/data:/var/lib/registry \ > registry:2 aaacfe335903929d783c5003ec554b4e351f362df67760a8b29c6b11d0a5b46a ここにイメージをpushします。 【クライアント作業】 $ docker login ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5003 Login Succeeded $ docker push ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5003/alpine:test The push refers to repository [ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5003/alpine] b2d5eeeaba3a: Pushed $ curl -u test:test http://ec2-54-250-153-222.ap-northeas t-1.compute.amazonaws.com:5003/v2/_catalog {"repositories":["alpine"]} 問題なくpushできました。dataディレクトリも共有されています $ ll total 8 -rw-rw-r-- 1 ec2-user ec2-user 299 May 8 13:35 config.yml drwxrwxr-x 3 ec2-user ec2-user 20 May 8 14:13 data -rw-rw-r-- 1 ec2-user ec2-user 66 May 5 09:18 test.htpasswd $ tree data/ data/ mqq docker mqq registry mqq v2 tqq blobs x?? mqq sha256 x?? tqq 54 x?? x?? mqq 540db60ca9383eac9e418f78490994d0af424aab7bf6d0e47ac8ed4e2e9bcbba x?? x?? mqq data x?? tqq 6d x?? x?? mqq 6dbb9cc54074106d46d4ccb330f2a40a682d49dda5f4844962b7dce9fe44aaec x?? x?? mqq data x?? mqq de x?? mqq def822f9851ca422481ec6fee59a9966f12b351c62ccb9aca841526ffaa9f748 x?? mqq data mqq repositories mqq alpine tqq _layers x?? mqq sha256 x?? tqq 540db60ca9383eac9e418f78490994d0af424aab7bf6d0e47ac8ed4e2e9bcbba x?? x?? mqq link x?? mqq 6dbb9cc54074106d46d4ccb330f2a40a682d49dda5f4844962b7dce9fe44aaec x?? mqq link tqq _manifests x?? tqq revisions x?? x?? mqq sha256 x?? x?? mqq def822f9851ca422481ec6fee59a9966f12b351c62ccb9aca841526ffaa9f748 x?? x?? mqq link x?? mqq tags x?? mqq test x?? tqq current x?? x?? mqq link x?? mqq index x?? mqq sha256 x?? mqq def822f9851ca422481ec6fee59a9966f12b351c62ccb9aca841526ffaa9f748 x?? mqq link mqq _uploads 28 directories, 8 files 一度コンテナを削除し、pullできるか確認してみます。イメージは削除済みです。 【サーバ作業】 $ docker rm -f registry-volume $ docker run -d -p 5003:5000 --restart=always --name registry-volume \ -v `pwd`/config.yml:/etc/docker/registry/config.yml \ -v `pwd`/test.htpasswd:/auth/htpasswd \ -v `pwd`/data:/var/lib/registry \ registry:2 【クライアント作業】 ### リポジトリの有無を確認 $ curl -u test:test http://ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5003/v2/_catalog ### 再度pullできるか確認 $ docker pull ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5003/alpine:test test: Pulling from alpine 540db60ca938: Already exists Digest: sha256:def822f9851ca422481ec6fee59a9966f12b351c62ccb9aca841526ffaa9f748 Status: Downloaded newer image for ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5003/alpine:test ec2-54-250-153-222.ap-northeast-1.compute.amazonaws.com:5003/alpine:test 問題なくできました。コンテナのデータを残しておくために、必要なデータはホストや外部サーバと共有しましょう 最後に パスワード認証が必要なdocker-registryを導入できました。 次はhttps接続できるようにしたいと思います。 参考 registryデプロイ https://docs.docker.com/registry/deploying/ タグ設定 https://docs.docker.com/engine/reference/commandline/tag/#tag-an-image-for-a-private-repository http接続のためのdocker-daemon設定 https://docs.docker.com/registry/insecure/ パスワードを設定 https://docs.docker.com/registry/deploying/#native-basic-auth https://docs.docker.com/registry/configuration/#htpasswd ストレージ設定 https://docs.docker.com/registry/configuration/#storage https://github.com/docker/docker.github.io/blob/master/registry/storage-drivers/filesystem.md ログ設定 https://docs.docker.com/registry/configuration/#log ボリューム共有 https://docs.docker.com/registry/deploying/#customize-the-storage-location 参考にさせていただきました。ありがとうございます。 https://qiita.com/Brutus/items/da63d23be32d505409c6
- 投稿日:2021-05-09T08:28:19+09:00
開発用のMySQL Dockerコンテナのメモリ消費が大きくて辛かったのでperformance_schemaを無効にしてどれくらい減るか調べたメモ
開発時に手元のマシンでコンテナを2個、3個と同時に動かさないといけない場面があって辛い 特に MySQL 5.6。扱うデータが少量でも 400MB を越える。 データちょっとしか入れてないのに? MySQL ってそういうものなの……?? あれこれ調べてパフォーマンススキーマを無効にする方法に辿りついた 以下、どのくらい減るかを調べたメモです。 ※ 無効にして問題ないのかという点については断定を避け(詳しくないので)、この記事では無効にしたときにどのくらいメモリ消費が減るか調べたことについてのみ書きます。ただ、軽く調べた限りでは、障害の調査やパフォーマンスチューニングをしないのであれば、開発用途では無効にしても不都合はなさそうに思えました。 結果 ※ 以下、"ps" と書いているのは performance_schema の略です。 起動した後のメモリ使用量(docker stats で表示される値): MySQL のバージョン ps = ON(MiB) ps = OFF(MiB) 5.6.61 464.6 59.8 5.7.34 194.3 62.7 8.0.24 335.9 118.6 5.6.61 では無効にすることで 88%減りました また、5.7 でメモリ消費がかなり改善されたことが分かります。 show engine performance_schema status でパフォーマンススキーマ全体でのメモリ使用量を見てみると次のようになっており、上記で減った量とほぼ一致していました。 MySQL のバージョン performance_schema.memory (MiB) 5.6.61 403.9 5.7.34 131.3 8.0.24 208.4 調査方法 使ったもの ホスト: Ubuntu 18.04 MySQL の公式 Docker イメージ Sakila サンプルデータ ディレクトリ・ファイル配置 - (作業用ディレクトリ) - sakira-db/ - 0_sakila-schema.sql - 1_sakila-data.sql - conf.d/ - my.cnf conf.d/ と sakila-db/ をそれぞれマウントして読み込ませました。下記のスクリプト参照。 conf.d/my.cnf [mysqld] # デフォルトで ON performance_schema=OFF 調査用スクリプト client.sh #!/bin/bash CONTAINER_NAME=mysql-sakila docker exec -it -e MYSQL_PWD=root $CONTAINER_NAME \ mysql --protocol=tcp -uroot -Dsakila "$@" restart.sh #!/bin/bash CONTAINER_NAME=mysql-sakila TIMEOUT_SEC=120 # MYSQL_VER=5.6.51 # MYSQL_VER=5.7.34 MYSQL_VER=8.0.24 # 動いていたら止める if (docker ps --format "{{.Names}}" | grep '^'${CONTAINER_NAME}'$' > /dev/null); then docker stop $CONTAINER_NAME fi # mysqld 起動 docker run --rm -it \ -e MYSQL_ROOT_PASSWORD=root \ -v "$(pwd)/conf.d:/etc/mysql/conf.d" \ -v "$(pwd)/sakila-db:/docker-entrypoint-initdb.d" \ --name $CONTAINER_NAME \ -d \ mysql:$MYSQL_VER # mysqld の起動完了を待って exit for i in $(seq $TIMEOUT_SEC); do if (./client.sh -e "select 1" > /dev/null 2>&1); then printf "\n" echo "ok" exit 0 else printf "." sleep 1 fi done echo "failed" exit 1 ps_info.sh #!/bin/bash set -o xtrace ./client.sh -e " show variables like 'performance_schema' " # パフォーマンススキーマ全体でのメモリ使用量 ./client.sh -e " show engine performance_schema status " | grep 'performance_schema.memory' 参考 MySQL :: MySQL 8.0 リファレンスマニュアル :: 27 MySQL パフォーマンススキーマ (dev.mysql.com) (2016) performance_schemaをsysで使い倒す! | Think IT(シンクイット) (2016) t2.nano で MySQL5.6 を動かすために | ゲンジニア日記
- 投稿日:2021-05-09T02:04:51+09:00
docker composeでWordPressを試したときの失敗談
Dockerの学習をぼちぼち進めている。 Software Design誌の2020年12月号の第1特集に、Docker Composeの初歩としてWordPressを動かすサンプルが掲載されている。これを動かすまでの過程で一つハマったので、備忘として記録しておく。ハマりの原因は、もちろん自分のミスにある。 やろうとしたこと 雑誌に掲載しているdocker-compose.yml を使用して、WordPressとMySQLのコンテナからなるアプリケーションを実行する。 なお雑誌掲載の docker-compose.yml は、Docker Hubの公式WordPressイメージに載っているものとほぼ同じ内容。 ハマりの内容 docker-compose.yml を作成する際に編集を誤り、WordPressコンテナとMySQLコンテナのそれぞれに設定するDBユーザー名(WORDPRESS_DB_USER, MYSQL_USER)が一致しない状態になっていた。 この状態でdocker-compose upでアプリケーションを起動し、http://localhost:8080/ のURLでWordPressにアクセスしようとしたところ、(当然の結果として)WordPressがデータベースの接続に失敗し、ブラウザに "Error Establishing a Database Connection"のエラーメッセージが出た。同時に、MySQLコンテナに下記のログが出た。 [Note] Access denied for user 'exampleuser'@'172.19.0.3' (using password: YES) docker-compose.yml の誤りを修正した後で、コンテナとイメージを削除して再度アプリケーションを起動しようとしたが、エラーが解消されなかった。 雑誌掲載の docker-compose.yml の代わりに、公式WordPressイメージのサンプルをまるまる上書きコピーしてアプリケーションを起動しても、同じくエラーが解消されなかった。 原因 最初に誤った docker-compose.yml を使用してコンテナを起動したときに、誤った設定情報をもとにWordPress用/MySQL用のそれぞれにボリュームができた。 docker-compose.ymlを修正しても、一度できたボリュームは前回の誤った設定を保持したままになっていた。 2回目以降に起動したコンテナが誤った設定を持ったままのボリュームを参照していたために、エラーが解消されなかった。 対応 誤ったdocker-compose.ymlをもとにできたボリュームを削除してアプリケーションを再起動し、正しい設定でボリュームを再作成する。 docker-compose down -v でコンテナと同時にボリュームも消す % docker-compose down -v Removing wordpress-sd2020dec_wordpress_1 ... done Removing wordpress-sd2020dec_db_1 ... done Removing network wordpress-sd2020dec_default Removing volume wordpress-sd2020dec_wordpress Removing volume wordpress-sd2020dec_db docker-compose up でアプリケーションを再起動すると、ボリュームが正しい設定で再作成される 余談:docker compose rm -vではボリュームが消えない(2021/05/09時点) Docker Desktop for Mac/for Windowsのバージョン3.2.1以降では、dockerコマンドにcompose CLIが統合されている。そのため、ハイフンをつけないdocker compose down -vコマンドでもボリュームが消せるはずなのだけれど、実際にはボリュームが削除されなかった(Docker version 20.10.6, build 370c289 on macOS Big Sur 11.3.1)。 この事象はcompose CLIのIssuesで報告されていて(https://github.com/docker/compose-cli/issues/1553) 、修正のプルリクエストも上がっている(https://github.com/docker/compose-cli/pull/1618) ようなので、いずれ修正版がリリースされるのだろう。 余談:解決までの経緯 Docker Hubの公式WordPressイメージを見たが、収穫なし docker wordpress access denied for user をキーワードにググったところ、今回に類似した事象の報告として https://forums.docker.com/t/wordpress-example-in-docker-compose-fails/30438 を発見。日本語でも同様のことを書いたブログ記事があった(https://swan-once.com/docker-compose-yml_forwordpress/) 。 これらの記事では、解決法として「docker-compose.ymlを修正し、MySQL用ボリュームをマウントする先のディレクトリー設定を、元の /var/lib/mysql から /var/lib/mysql2 などに変更する」という方法が示されていた しかし「公式サイトのサンプルを変えないと動かない」というのは不自然で、真の解決法は別にあるはず コンテナ自体は前回起動時のことを覚えていないはずだし、…と考えた結果、「ボリュームに古い情報が残っている」ことに気づいた
- 投稿日:2021-05-09T01:26:53+09:00
DockerでEC-cube4をPgAdmin付きで構築する。
前提 Dockerデスクトップをインストール済み gitコマンドインストール済み 筆者の環境 MacOSX Bigsur M1チップMacBookPro このやり方で構築に成功した日。 2021年5月9日。 EC-cube4のプロジェクトをgitクローンする。 git clone https://github.com/EC-CUBE/ec-cube.git DockerComposeファイルを編集する。 postgresとpgAdminの設定を以下のように書く。 docker-compose.pgsql.yml version: '3' volumes: pg-database: driver: local services: ec-cube: depends_on: - postgres environment: DATABASE_URL: "postgres://dbuser:secret@postgres/eccubedb" DATABASE_SERVER_VERSION: 10 postgres: image: postgres:10 environment: POSTGRES_DB: eccubedb POSTGRES_USER: dbuser POSTGRES_PASSWORD: secret ports: - 15432:5432 volumes: - pg-database:/var/lib/postgresql/data networks: - backend ### pgadmin4の設定を追記する。 pgadmin4: image: dpage/pgadmin4 container_name: pgadmin4 ports: - 8100:80 volumes: - ./pgadmin:/var/lib/pgadmin/storage environment: PGADMIN_DEFAULT_EMAIL: dotnsf@xxxx.com PGADMIN_DEFAULT_PASSWORD: P@ssw0rd hostname: pgadmin4 restart: always networks: - backend docker-composeは以下のように書く。 docker-compose.yml version: "3" networks: backend: driver: bridge volumes: mailcatcher-data: driver: local ### ignore folder volume ##### var: driver: local vendor: driver: local node_modules: driver: local services: ### ECCube4 ################################## ec-cube: build: context: . args: # ビルド時のECCubeインストールスクリプトをスキップする場合にtrueを指定する。 # ビルド時点でDBサーバの起動や接続が出来ない、という場合等にエラーとなるため。 SKIP_INSTALL_SCRIPT_ON_DOCKER_BUILD: "true" ports: - 8090:80 - 4430:443 volumes: ### 同期対象からコストの重いフォルダを除外 ##################### - "var:/var/www/html/var" - "vendor:/var/www/html/vendor" - "node_modules:/var/www/html/node_modules" environment: # EC-CUBE environments APP_ENV: "dev" APP_DEBUG: 1 DATABASE_URL: "postgres://dbuser:secret@postgres/eccubedb" DATABASE_SERVER_VERSION: 3 MAILER_URL: "smtp://mailcatcher:1025" ECCUBE_AUTH_MAGIC: "<change.me>" ECCUBE_LOCALE: "ja" ECCUBE_TIMEZONE: "Asia/Tokyo" ECCUBE_CURRENCY: "JPY" ECCUBE_ADMIN_ROUTE: "admin" ECCUBE_USER_DATA_ROUTE: "user_data" # ECCUBE_ADMIN_ALLOW_HOSTS: [] # ECCUBE_FORCE_SSL: false # ECCUBE_TEMPLATE_CODE: "default" # ECCUBE_COOKIE_NAME: "eccube" # ECCUBE_COOKIE_PATH: "/" # ECCUBE_COOKIE_LIFETIME: 0 # ECCUBE_GC_MAXLIFETIME: 1440 ECCUBE_ADMIN_USER: "admin" ECCUBE_ADMIN_PASS: "password" networks: - backend ### Mailcatcher ################################## mailcatcher: image: schickling/mailcatcher ports: - "1080:1080" - "1025:1025" networks: - backend ローカル側にPGAdminをマウントするためのフォルダを作成する ローカル側のEC-cubeをgit cloneしたプロジェクトルートで、 docker-compose.pgsql.ymlに記述したvolumesのコロンの手前の文字列と同じ名前のディレクトリを作成する。 mkdir pgadmin コンテナを立ち上げる。 プロジェクトルートで公式のpgsql用と書いてあるコマンドをコピペして実行する。 docker compose -f docker-compose.yml -f docker-compose.pgsql.yml -f docker-compose.dev.yml up -d 初回のインストールコマンドを打つ。 公式のコマンドを打つと、DBのマイグレートとシーダーなどの初期化をやってくれる。 これを忘れるとTableがないというエラーになる。 docker-compose exec -u www-data ec-cube bin/console eccube:install -n アクセスする。 ここまででアクセスできると思うので、 ECcube4へは localhost:8090 pgAdminへは localhost:8100 をブラウザに打ち込んでアクセスする。 ポート番号は上のymlで設定している番号になるので任意の番号に変更可。 筆者はMAMPで80番を使いたいのでこのように変えています。 ログイン後のpgAdminのDBコネクション設定 下のページの解説の通りに設定したらできたので続きはそちらをみてください。 補足・ポイント・困ったことなど services:の数だけコンテナが別々に立ち上がる。 各サービスのnetworks:の値を揃えることで、コンテナ同士が連携して通信できるようになり、一つのアプリケーションとして機能する。 pgAdminはローカルのどこにマウントしても構わない。ただし、そのフォルダは予め用意しておくこと。 筆者はpostgresのdbのパスと同じかと思い、docker compose upはできるがアクセスすると弾かれるという現象でハマりました。 今回はもうpostgresでやりたいことができたので諦めましたが、本当はmySQLで構築しようとしていました。 しかし、公式のmySQL用コマンドではdocker compose up できず、エラーでこけてしまっていました。 tagを消してlatestにしてもダメだったので、M1チップに対応したイメージがdockerHubにないのかもしれません。 M1マックの人はpostgresを使った方が無難です。(2021/05/09現在) (2021/05/10追記) 以下の記事の通りにやるとM1チップでもmysqlをインストールできるようになりました。 やぱりCPUが悪いようです。 docker-compose(またはdocker-compose -fで読み込むyml)に以下を追記する。 追記場所はservice:がmysqlのブロック。 docker-compose.yaml platform: linux/x86_64