- 投稿日:2019-12-18T23:44:44+09:00
Docker コンテナ内から他の Docker コンテナにdocker exec実行
AWS Workspaces
Amazon Linux2
nginx 1.16.1DockerfileFROM alpine:3.10.3 RUN apk --update add logrotate docker && rm -rf /var/cache/apk/* # cronのdaemonを起動(log level=1, foreground) CMD crond -l 1 -f# Dockerイメージ作成 docker build -t base . # Dockerコンテナ起動 docker run -d \ --name nginx \ -p 81:80 \ nginx:1.16.1 docker run -d \ --name base \ -v /var/run/docker.sock:/var/run/docker.sock \ base:latest $ docker exec -it base sh / # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 34f2c8645bd2 base:latest "/bin/sh -c 'crond -…" 18 seconds ago Up 17 seconds base e48c7a09b233 nginx:1.16.1 "nginx -g 'daemon of…" 42 minutes ago Up 42 minutes 0.0.0.0:81->80/tcp nginx / # docker exec -it nginx bash root@e48c7a09b233:/# ls bin dev home lib64 mnt proc run srv tmp var boot etc lib media opt root sbin sys usr root@e48c7a09b233:/# nginx -v nginx version: nginx/1.16.1
- 投稿日:2019-12-18T23:35:45+09:00
誕生日にCTFを開催してみた
TL;DR
- CTF開催にCTFdは非常に便利
- GCE上でDockerコンテナを11個立てていたが, 問題なく動いた
- 開催日程は事前に発表しておくと良い
もくじ
はじめに
2019年12月5日 0:00から2019年12月6日 0:00までの1日間にtaskCTFを開催しました。
taskCTFの開催にあたり行った環境構築や, CTF自体の振り返りを共有するために本記事を投稿します。
なお, taskCTFで使用した問題はGitHubで公開しています。
Dockerfile等のconfigファイル群, 問題およびwriteupが入れてあるので, もしよければご参照ください。
task4233/taskctf19ご参加いただいた方々はありがとうございました!
おかげさまで非常に思い出に残る誕生日になりました。CTFの環境構築
GCEのインスタンス上でDockerコンテナを11個立てました。
内訳は以下の通りです。
- Web問サーバ2個
- Pwn問サーバ5個
- コンテストサーバ4個
GCEをしっかり使ったことが無かったため, 以下の記事を参考にして環境構築を行いました。特に困ったことはありませんでした。
これらのコンテナは大きく分けて以下の3つのグループに分けられます。
コンテストサーバ(CTFd)
以下の4つのコンテナはスコアサーバである, CTFdのために使用しました。
- CTFd
- DB
- Radius
- Postfix
CTFdはdocumentationがあり非常に楽でした。
install方法は, flaskで手動立ち上げかdocker runかdocker-compose upが使用できたため, docker-compose upで楽をしました。結果的に問題なく動いてくれたので良かったです。
先日参加したCTFのイベントでも運営の方にお聞きしたところ, 「CTFdを使い初めてからコンテストサーバが落ちたことがない」とのことだったので, CTFdは運用面で信頼性が高そうです(内部でradiusが動いているので分散もうまいことやってくれます)
Web問サーバ
以下の2つのコンテナはWeb問サーバに使用しました。
- Bad Frontend-1
- Bad-Frontend-2
php-fpmの公式イメージを使っていました。
以下, Dockerfileです。
// Dockerfile FROM php:7.2-fpm COPY php.ini /usr/local/etc/php CMD ["php", "-S", "0.0.0.0:80"]今回のWeb問はサーバにリクエストを送りつける問題だったので, 負荷が心配でしたが全く問題なかったようでした。
ちなみに, ローカルのPCからDOSもどきをしたのですが, GCEのCPU負荷を見ると殆ど影響がない様子でした。
アプリケーション自体の負荷が少なかっただけかもしれませんが, 結果的に何も起きなかったので良かったです。Pwn問サーバ
以下の5つのコンテナをPwn問サーバに使用しました。
- peep
- loop
- leetspeak
- 334
- peep2
このうち, 上の3つは予想通りの実行が為されなかったため, 実際にポートを公開したのは下の2つのみでした。
今思うと, tcpで公開していたので, udpで公開した方がよかったのかもしれません。
Hostingにはmegumishさんに助言をいただき, xinetdを利用しました。
https://twitter.com/megumish/status/1202466987332341760?s=20
1時間くらいで構築したので, 変な部分があるかもしれません。
以下, Dockerfileです。
// Dockerfile FROM ubuntu:16.04 RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.ustc.edu.cn/g" /etc/apt/sources.list RUN apt-get update && apt-get -y upgrade RUN apt-get install -y lib32z1 xinetd CMD ["/usr/sbin/xinetd", "-dontfork"]このxinetdでホスティングしたものの, buffer overflowを狙った問題は正しくnetcatで繋がりませんでした。
format string attackを使う問題では問題なかったんですが......
原因がよくわからないので, xinetdについてわかる方がいれば助言をください。CTFの運用
以下がCPUの使用率です。
ホスティング時の3日とコンテスト終了間際にかなり高くなっています。
ネットワークのパケットトラフィックを見ると, 同じような時間帯に受信パケが多くなっています。そのため, Pwn問追加直後の影響だと考えられます。
絶対にサーバを落としてはならないと考えていたため, トラフィックが集中すると考えていた当初は, Pwn問を公開せずにコンテナ数を5つにしていました。
想定していたよりも負荷が少ない様子だったので, もっとコンテナを増やしても良かったのかもしれません。
何はともあれ, 結果的に安定したホスティングができ, 良かったと考えています。開催したCTFの振り返り
開催後にアンケートを取り, 20人から回答が得られました。
全体の95%もの方が「楽しめた」と回答してくださり, 非常に嬉しかったです。良かった点として頂いたご意見は, 大きく分けて以下の4点でした。
- 理不尽なエスパー問題が無かった点
- Pwn問があった点
- 難しすぎず初心者でも楽しめた点
- サーバが安定していた点
悪かった点として頂いたご意見は, 大きく分けて以下の6点でした。
- 問題追加が遅かった点
- 問題ジャンルが少なかった点
- 同じ解法で解ける問題があった点
- 開催するタイミングが事前公開されなかった点
- 開催時間が分かりにくかった点
- Miscが多すぎた点
問題追加が遅かった点
問題ジャンルが少なかった点申し訳なかったです。しかし, できる全力を尽くしたので, 温かい目で見ていただきたいです。
同じ解法で解ける問題があった点
Pwn問とWeb問についてです。
Pwn問では, FSAで解ける問題でFlagが同じ場所にあったため同じコードでFlagが取れてしまったようです。
常識なのかもしれませんが, Flagの宣言場所は変えた方が良いようでした。
Web問では, 同様にローカルプロキシを使っている方は同じ解法で溶けてしまったようです。もう少しひねった方が良かったかもしれないです。Miscが多すぎた点
Miscが多すぎたというか, 他ジャンルが少なかったということだと思います。
おわりに
以上, 環境構築とコンテストの反省でした。
今回製作した問題は, 理不尽問題をなくすつもりで作っていたので, 感想で「理不尽問がなかった」という感想をいただけて非常に嬉しかったです。感想等はTwitterのハッシュタグ#taskctfをご覧ください。
また, 環境構築や運用において不明点等があれば, 答えられる範囲で答えたいので, お気軽にお聞きください!
ここまでお読みいただきありがとうございました!
あなたも誕生日にCTFを開催してみてはいかがでしょうか?
- 投稿日:2019-12-18T23:35:45+09:00
誕生日に開催したCTFの環境構築と振り返り
TL;DR
- CTF開催にCTFdは非常に便利
- GCE上でDockerコンテナを11個立てていたが, 問題なく動いた
- 開催日程は事前に発表しておくと良い
もくじ
はじめに
誕生日なのでCTFを開催するか, と言う気持ちで,
2019年12月5日 0:00から2019年12月6日 0:00までの1日間にtaskCTFを開催しました。taskCTFの開催にあたり行った環境構築や, CTF自体の振り返りを共有するために本記事を投稿します。
なお, taskCTFで使用した問題はGitHubで公開しています。
Dockerfile等のconfigファイル群, 問題およびwriteupが入れてあるので, もしよければご参照ください。
task4233/taskctf19ご参加いただいた方々はありがとうございました!
おかげさまで思い出に残る誕生日になりました。CTFの環境構築
GCEのインスタンス上でDockerコンテナを11個立てました。
内訳は以下の通りです。
- Web問サーバ2個
- Pwn問サーバ5個
- コンテストサーバ4個
GCEをしっかり使ったことが無かったため, 以下の記事を参考にして環境構築を行いました。特に困ったことはありませんでした。
これらのコンテナは大きく分けて以下の3つのグループに分けられます。
コンテストサーバ(CTFd)
以下の4つのコンテナはスコアサーバである, CTFdのために使用しました。
- CTFd
- DB
- Radius
- Postfix
CTFdはdocumentationがあり非常に楽でした。
install方法は, flaskで手動立ち上げかdocker runかdocker-compose upが使用できたため, docker-compose upで楽をしました。結果的に問題なく動いてくれたので良かったです。
先日参加したCTFのイベントでも運営の方にお聞きしたところ, 「CTFdを使い初めてからコンテストサーバが落ちたことがない」とのことだったので, CTFdは運用面で信頼性が高そうです(内部でradiusが動いているので分散もうまいことやってくれます)
Web問サーバ
以下の2つのコンテナはWeb問サーバに使用しました。
- Bad Frontend-1
- Bad-Frontend-2
php-fpmの公式イメージを使っていました。
以下, Dockerfileです。
// Dockerfile FROM php:7.2-fpm COPY php.ini /usr/local/etc/php CMD ["php", "-S", "0.0.0.0:80"]今回のWeb問はサーバにリクエストを送りつける問題だったので, 負荷が心配でしたが全く問題なかったようでした。
ちなみに, ローカルのPCからDOSもどきをしたのですが, GCEのCPU負荷を見ると殆ど影響がない様子でした。
アプリケーション自体の負荷が少なかっただけかもしれませんが, 結果的に何も起きなかったので良かったです。Pwn問サーバ
以下の5つのコンテナをPwn問サーバに使用しました。
- peep
- loop
- leetspeak
- 334
- peep2
このうち, 上の3つは予想通りの実行が為されなかったため, 実際にポートを公開したのは下の2つのみでした。
今思うと, tcpで公開していたので, udpで公開した方がよかったのかもしれません。
Hostingにはmegumishさんに助言をいただき, xinetdを利用しました。
https://twitter.com/megumish/status/1202466987332341760?s=20
1時間くらいで構築したので, 変な部分があるかもしれません。
以下, Dockerfileです。
// Dockerfile FROM ubuntu:16.04 RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.ustc.edu.cn/g" /etc/apt/sources.list RUN apt-get update && apt-get -y upgrade RUN apt-get install -y lib32z1 xinetd CMD ["/usr/sbin/xinetd", "-dontfork"]このxinetdでホスティングしたものの, buffer overflowを狙った問題は正しくnetcatで繋がりませんでした。
format string attackを使う問題では問題なかったんですが......
原因がよくわからないので, xinetdについてわかる方がいれば助言をください。CTFの運用
以下がCPUの使用率です。
ホスティング時の3日とコンテスト終了間際にかなり高くなっています。
ネットワークのパケットトラフィックを見ると, 同じような時間帯に受信パケが多くなっています。そのため, Pwn問追加直後の影響だと考えられます。
絶対にサーバを落としてはならないと考えていたため, トラフィックが集中すると考えていた当初は, Pwn問を公開せずにコンテナ数を5つにしていました。
想定していたよりも負荷が少ない様子だったので, もっとコンテナを増やしても良かったのかもしれません。
何はともあれ, 結果的に安定したホスティングができ, 良かったと考えています。開催したCTFの振り返り
開催後にアンケートを取り, 20人から回答が得られました。
全体の95%もの方が「楽しめた」と回答してくださり, 非常に嬉しかったです。良かった点として頂いたご意見は, 大きく分けて以下の4点でした。
- 理不尽なエスパー問題が無かった点
- Pwn問があった点
- 難しすぎず初心者でも楽しめた点
- サーバが安定していた点
悪かった点として頂いたご意見は, 大きく分けて以下の6点でした。
- 問題追加が遅かった点
- 問題ジャンルが少なかった点
- 同じ解法で解ける問題があった点
- 開催するタイミングが事前公開されなかった点
- 開催時間が分かりにくかった点
- Miscが多すぎた点
問題追加が遅かった点
問題ジャンルが少なかった点申し訳なかったです。しかし, できる全力を尽くしたので, 温かい目で見ていただきたいです。
同じ解法で解ける問題があった点
Pwn問とWeb問についてです。
Pwn問では, FSAで解ける問題でFlagが同じ場所にあったため同じコードでFlagが取れてしまったようです。
常識なのかもしれませんが, Flagの宣言場所は変えた方が良いようでした。
Web問では, 同様にローカルプロキシを使っている方は同じ解法で溶けてしまったようです。もう少しひねった方が良かったかもしれないです。Miscが多すぎた点
Miscが多すぎたというか, 他ジャンルが少なかったということだと思います。
おわりに
以上, 環境構築とコンテストの反省でした。
今回製作した問題は, 理不尽問題をなくすつもりで作っていたので, 感想で「理不尽問がなかった」という感想をいただけて非常に嬉しかったです。感想等はTwitterのハッシュタグ#taskctfをご覧ください。
また, 環境構築や運用において不明点等があれば, 答えられる範囲で答えたいので, お気軽にお聞きください!
ここまでお読みいただきありがとうございました!
あなたも誕生日にCTFを開催してみてはいかがでしょうか?
- 投稿日:2019-12-18T23:26:23+09:00
jib-maven-pluginを使ってSpringBootアプリをイメージ化してDockerで起動
はじめに
この記事は、Java Advent Calendar 2019 - Qiita 23日目の記事です。
皆さん、コンテナ使ってますか??
Googleが公開しているjib-maven-pluginを使用すれば、Javaで作成されたアプリを簡単にDockerイメージにすることができます。
今回はSpringBoot・Mavenを使用したSpringBootアプリケーションのイメージビルド及びコンテナ立ち上げまでやってみます(本当はAWSデプロイまでやりたかったけど時間がないので断念)環境
- Java8
- SpringBoot2.1.9.RELEASE
- Maven3.6.3
- jib-maven-plugin1.8.0
- Docker19.03.5
SpringBootアプリケーションを構築する
SpringBoot・Mavenで構築されたプロジェクトを作成します。
Springから提供されているSpring Initializrを使用すれば簡単にアプリケーションを構築することができます。
使用方法はこちら(後日使用方法をアップします)サンプルControllerの追加
Webアプリケーションを今回は作成するので、サンプルのController及びhtmlを追加します。
IndexController
@Controller public class IndexController { @GetMapping("/") public ModelAndView get(ModelAndView mav) { mav.setViewName("index"); return mav; } }index.html
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>JibSampleApp</title> <!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <!-- Optional theme --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> <!-- Latest compiled and minified JavaScript --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> </head> <body> <div class="container"> <div class="row"> <div class="jumbotron"> <h1>JibSampleApp</h1> <p>this app is JibSampleApp</p> </div> <div class="panel panel-success"> <div class="panel-heading">blank</div> <div class="panel-body"></div> </div> </div> </div> </body> </html>プラグインを設定
上記で作成したSpringBootアプリケーションのpomに以下のプラグインを追加します。
pom.xml
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>1.8.0</version> <configuration> <to> <image>jibsampleimage</image> </to> </configuration> </plugin>build実行
Dockerが起動している状態で、
mvn compile jib:dockerBuild
を実行することで、SpringBootアプリケーションのイメージbuildが実行されます。
Windowsなどで管理者権限を剥奪されている場合、うまく動作しないことがあるので、その場合は一時的に管理者権限を付与する必要があります。
buildがうまくいくと、Dockerのイメージ一覧の中に作成したイメージがあることが確認できます。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE jibsampleimage latest bcb3c6749044 49 years ago 161MBDockerコンテナ起動
上記でbuildしたイメージをもとにDockerコンテナを作成し、実行します。
以下のコマンドを入力することで、ローカルの8080ポートとDockerの8080をマッピングし、ブラウザからアクセスし確認することができます。
docker run -p 8080:8080 -it jibsampleimage
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.9.RELEASE) 2019/12/18 14:11:53.177 [main] INFO c.a.j.s.JibSampleApp Starting JibSampleApp on be8d974734e4 with PID 1 (/app/classes started by root in /) 2019/12/18 14:11:53.189 [main] INFO c.a.j.s.JibSampleApp No active profile set, falling back to default profiles: default 2019/12/18 14:11:56.123 [main] WARN o.m.s.m.ClassPathMapperScanner No MyBatis mapper was found in '[com.atu496.jib.sample]' package. Please check your configuration. 2019/12/18 14:11:58.065 [main] INFO o.s.b.w.e.t.TomcatWebServer Tomcat initialized with port(s): 8080 (http) 2019/12/18 14:11:58.166 [main] INFO o.a.c.h.Http11NioProtocol Initializing ProtocolHandler ["http-nio-8080"] 2019/12/18 14:11:58.213 [main] INFO o.a.c.c.StandardService Starting service [Tomcat] 2019/12/18 14:11:58.217 [main] INFO o.a.c.c.StandardEngine Starting Servlet engine: [Apache Tomcat/9.0.26] 2019/12/18 14:11:58.535 [main] INFO o.a.c.c.C.[.[.[/] Initializing Spring embedded WebApplicationContext 2019/12/18 14:11:58.537 [main] INFO o.s.w.c.ContextLoader Root WebApplicationContext: initialization completed in 5194 ms 2019/12/18 14:11:59.277 [main] INFO o.s.s.c.ThreadPoolTaskExecutor Initializing ExecutorService 'applicationTaskExecutor' 2019/12/18 14:11:59.532 [main] INFO o.s.b.a.w.s.WelcomePageHandlerMapping Adding welcome page template: index 2019/12/18 14:12:00.865 [main] INFO o.a.c.h.Http11NioProtocol Starting ProtocolHandler ["http-nio-8080"] 2019/12/18 14:12:01.033 [main] INFO o.s.b.w.e.t.TomcatWebServer Tomcat started on port(s): 8080 (http) with context path '' 2019/12/18 14:12:01.050 [main] INFO c.a.j.s.JibSampleApp Started JibSampleApp in 9.135 seconds (JVM running for 10.809)起動できていることが確認できると思います。
終わりに
SpringBootアプリケーションの簡単なイメージの作成及びコンテナ起動することができました。
ただ、これはまだローカルでの話なので、時間ができ次第AWS・GCP・Azureのコンテナ実行環境へのデプロイ方法をまとめる予定です(本来はそっちがメインだった。。。)
今回作成したソースコードはGithub上にアップしています。
- 投稿日:2019-12-18T22:46:37+09:00
ARMベースのEC2インスタンスを利用する
この記事は、ニフティグループ Advent Calendar 2019 の18日目の記事です。
昨日は @fuku710 さんのハッカソンのハックためになりましたね!
私は今月 AWS re:Invent 2019 に参加してきたのですが、同イベント中にも Hackathons and Jams というハッカソンが開催されていたので、次の機会があれば、@fuku710 さんの記事を参考にしながら参加したいですね!残念ながら、ハッカソンには参加できませんでしたが、たくさんのセッションやワークショップに参加したので、その中から ARM ベースのEC2インスタンスを利用するワークショップ CMP306 - Getting started with Arm-based Amazon EC2 instances を紹介したいと思います。
はじめに
AWS の ARM への取り組みは 2004年 Amazon Lab126 (Kindle などを作っているチーム) から始まったそうです。その後、ネットワークのオフロードや Nitro システムの構築など、カスタムシリコンの開発に情熱的に取り組んできたようです。
今年は Graviton2 を採用した次世代の ARM インスタンス(M6g/R6g/C6g)も発表されました。Graviton と比べると性能も7倍に上がったようですし、コストも20%程度は削減できるということで、是非一度使ってみたい!と思いワークショップに参加しました。
ワークショップの内容
1. arm64 で Java を動かす
Amazon Corretto を使用したアプリを A1インスタンスで動作させます。
- インスタンスの作成(AMI は Amazon Linux 2 を選択し、アーキテクチャに 64-bit Arm を選ぶこと)
- SSH でログインし Amazon Corretto 8 を
amazon-linux-extras
でインストールします- 同様に
amazon-linux-extras
でtomcat8.5
もインストールし簡単のJSPを用意します- セキュリティグループで 8080 を開けて結果が表示されれば成功です!簡単ですね!
2. x86 と arm64 インスタンス混在でコンテナを動かす
- ELB のバックエンドに x86 と arm64 インスタンスを作成する(t3.small を追加)
docker buildx
を実行して x86 と arm64 のコンテナを同時に作成する3.arm64 で CodeBuild を実行し BB を動かす
参考資料(※ワークショップで使ったURLなので1ヶ月程度で消えるかも)
https://arthurpt-public-ui.s3-eu-west-1.amazonaws.com/reInvent2019-cmp306-arm-instances/index.html
- 投稿日:2019-12-18T21:52:10+09:00
ECS(Fargate)へssh接続してみた
はじめに
この記事はコンテナ勉強用として試したことまとめたものです。
ECS(Fargate)にsshログインする要件があったので実施したものをまとめました。Fargateについて
- Fargateにssh接続はできない。
- sshdをインストールして接続する必要がある。
テンプレート取得
- 以下リンクにsshd設定をしてdockerイメージ作成をしてくれるのでgit cloneする。
- https://github.com/sawanoboly/amazonlinux-sshd
git clone https://github.com/sawanoboly/amazonlinux-sshdイメージの作成
- 以下コマンドを実行してイメージを作成する。
- Dockerfileにsshdやawscliなどのインストール設定が書かれています。
docker build -t amazonlinux-sshd:latest .ECRにプッシュ
- ECRにログインする。
$(aws ecr get-login --no-include-email --region ap-northeast-1)
- タグ付けをする。
docker tag amazonlinux-sshd:latest 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-ecr-repo:latest
- プッシュする。
docker push 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-ecr-repo:latestECSデプロイの実施
ssh接続する
- 以下のような形でログイン確認ができる。
Last failed login: Wed Dec 18 12:44:50 UTC 2019 from kd111111111111.au-net.ne.jp on ssh:notty There was 1 failed login attempt since the last successful login. debug1: PAM: reinitializing credentials debug1: permanently_set_uid: 0/0 Environment: USER=root LOGNAME=root HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/aws/bin MAIL=/var/mail/root SHELL=/bin/bash SSH_CLIENT=100.100.100.100 56702 22 SSH_CONNECTION=100.100.100.100 56702 101.101.101.101 22 SSH_TTY=/dev/pts/0 TERM=xterm AWS_CONTAINER_CREDENTIALS_RELATIVE_URI=/v2/credentials/1e23t01a-7a1e-3761-bc27-fa4b8473938373 AWS_EXECUTION_ENV=AWS_ECS_FARGATE AWS_DEFAULT_REGION=ap-northeast-1 AWS_REGION=ap-northeast-1 -bash-4.2#
- ロールにS3へのアクセス権限を付与すればS3からファイルをダウンロードすることもできる。
- 既存設定だとssh切断した際にコンテナが停止されてしまうので必要に応じて設定する必要あり。
まとめ
- Fargateだとsshできないかと思っていたが、やろうと思えばできる。
- sshdをインストールする必要があるのに気付けなかった。
参考
- 投稿日:2019-12-18T19:57:42+09:00
drupalをdocker上で簡単に動かしたメモ
はじめに
drupalをDocker上で動かす記事はいくつかありますが、EC2だったり途中だったりでシンプルなものがなかったのでメモしておきます
参考手順
drupalとmariadbのイメージをdockerhubから取ってきておく
docker pull drupal
docker pull mariadb
以下のファイルを作成
docker-compose.yamlversion: "2" services: # PHP Web Server web: # Build the Drupal 7 image # https://hub.docker.com/r/_/drupal/ image: drupal:7 # Environment variables environment: # Drupal settings DRUPAL_PROFILE: standard DRUPAL_SITE_NAME: Drupal DRUPAL_USER: admin DRUPAL_PASS: admin DRUPAL_DBURL: mysql://drupal:drupal@database:3306/drupal ports: - "8000:80" volumes: - ./drupal:/app links: - database:database command: php -S 0.0.0.0:80 -t /app working_dir: /app restart: always # MySQL Server database: image: mariadb:10 environment: MYSQL_USER: drupal MYSQL_PASSWORD: drupal MYSQL_DATABASE: drupal MYSQL_ROOT_PASSWORD: '' MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' ports: - "3306:3306" restart: always volumes: - mysql-db:/var/lib/mysql volumes: mysql-db:
docker-compose up -d
Drupalのソースコードをダウンロード・解凍をして、./drupalディレクトリに配置。
Drupalこの時点のディレクトリ構成
.
├── docker-compose.yaml
└── drupal
docker ps -a
mariaDBのdockerIDをメモしておく
docker exec -it (mariaDBのdockerID) bash
mysql -u root -p
→パスワードは上記yamlのMYSQL_ROOT_PASSWORDなので空文字(そのままエンター)
MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | drupal | | information_schema | | mysql | | performance_schema | +--------------------+ 4 rows in set (0.001 sec)各種フォームには以下を入れて進んでいけば設定が終わります。
データベース名: drupal
データベースユーザー名: drupal
データベースパスワード: drupal
詳細設定で
ホスト名: databaseおわりに
これを費用¥0でクラウドにデプロイしてサイト運用したいです。
- 投稿日:2019-12-18T19:01:06+09:00
DockerFileの変更内容を環境に反映したい
- 投稿日:2019-12-18T18:54:46+09:00
【続】WSL2 + AWS Toolkit for Visual Studio Code + SAM local + DynamoDB local
自分用の備忘録程度にと思ったら、タイトルのせいか結構Viewされていて、見て頂いた方に申し訳なく、ちょっと後ろめたくなったので、少し補足します。
主に参考にした記事へのリンクですが。元々の記事の趣旨はvscode以外、全てWSL2(Ubuntu)のbash上で完結するlambda + dynamodbのローカル開発環境環境を作ってみたいと思い、試行した結果(元々はハマったことの共有)です。
モチベーションは、PowerShellが好きじゃない(食わず嫌い)MS-DOSなオッサンだけど、cmdよりbashが使いたいからです。
※Windows 10 Insider Preview 20H1が前提のため、自己責任でお願いします。
※最近は殆どありませんが、数か月前まで私の環境では1日数回グリーンバックが出てました。
※Windows Update自体がバグってたりすることもあります。
※辞めたいと思っても次のメジャーアップデートまでクリーンインストール以外で製品版に戻せません。製品版でやりたい人は2020年春まで待ってください。手順全体
- Windows 10 Insider Preview 20H1のインストールとWSL2のインストール
- docker desktop community 2.1.7.0(41536) edge
- WSL2(Ubuntu)に各種ソフトをインストール
- Python 3.7.5
- pip 19.3.1
- aws-cli 1.16.299
- aws-sam-cli 0.37.0
- DynamoDB local (docker image : amazon/dynamodb-local)
- SAM localから通信させるための設定
- Visual Studio Code 1.41.0
- AWS Toolkit for Visual Studio Code 1.4.0
- Remote - WSL 0.41.5
- SAM localでHello World
- NoSQL Workbench for Amazon DynamoDB (Preview)を使う
- SAM localからDynamoDB localに接続してみる
lambda + dynamodbなPythonコード環境をローカルで動かす。
1. Windows 10 Insider Preview 20H1のインストール
そもそも既知の不具合ありの状態です。
この辺を参考に、自分の環境で入れても大丈夫か判断してください。
Tattuの備忘Log以下の記事など参考にしてインストールしてください。
WSL 2 のインストール手順※2019/12/17現在、FastリングはDevelopment branchに変わりました。
※WSL2を使うだけならSlowリングからインストールしてください。「Linux ディストリビューションがインストールされていない場合は~」
のステップでは、Windows StoreからUbuntuをインストールしてから先に進みます。入れ終わったらお約束の「sudo apt update / sudo apt upgrade」をお忘れなく。
2. docker desktop community 2.1.7.0(41536) edge
公式からダウンロードしてインストールします。
WSL2 で Docker Desktop for Windows (Edge) を利用する設定が完了すると、ubuntu上でdockerをインストールしなくてもbashからdockerコマンドが使用できます。(便利!)
動作確認にbashから「docker info」してみてください。
3. WSL2(Ubuntu)に各種ソフトをインストール
Pythonかpipのインストールでは先にインストールしておくaptなパッケージが足らず1度やり直しています。
ご注意ください。3.1. Python / 3.2. pip
pyenvを入れて、そこからインストールしました。
Ubuntu 18.04 に pyenv と Python 3.7.2 をインストールしたメモ3.3. aws-cli 1.16.299
公式通りpipを使ってインストールしました。
pip自体は既に入っているかもしれないので「pip --version」で確認してみてください。https://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html
ローカルで使うだけなら「aws configure」のAccess KeyとSecret Access Keyはいい加減で構いません。
そもそもいらないような?
region は「ap-northeast-1」でいいと思います。3.4. aws-sam-cli 0.37.0
aws-cliと同様にpipを使っていれました。
AWS SAM で Hello World するこの記事と同じようにパッケージが足らず、途中でエラーになった気がします。
必要なパッケージをapt installで追加でいれて再試行したような気がしますが、参考にした記事を失念してしまいました。4. DynamoDB local (docker image : amazon/dynamodb-local)
普通にdocker runしてイメージを取ってきます。
dockerhubdocker network createして。
bash$ docker network create aws-local
docker runしたコンテナを停止してから、適当なディレクトリに「docker-compose.yml」を作成して、docker-compose upします。
docker-compose.ymlversion: "3" services: dynamodb: container_name: dynamodb-local image: amazon/dynamodb-local volumes: - ./data:/data ports: - 58000:8000 command: -jar DynamoDBLocal.jar -port 8000 -dbPath /data -sharedDb networks: - aws-local networks: aws-local: external: true「comannd:」の部分がjavaランタイムに渡す値です。この例ではカレントディレクトリ配下の「./data」に「shared-local-instance.db」を残して他と共有します。このファイルはSQLiteで弄れるらしいのですが、試してません。
bashuser@MYHOSTNAME:~/docker/dynamodb-local$ docker-compose up -d4.1. SAM localから通信させるための設定
「.bash_profile」(※1)にSAM_DOCKER_NETWORKを環境変数として追加します。
(※1)penvのインストール時に作ったはず。
.bash_profileexport SAM_DOCKER_NETWORK=aws-local export PYENV_ROOT=$HOME/.pyenv export PATH=$PYENV_ROOT/bin:$PATH eval "$(pyenv init -)" source ~/.bashrc5. Visual Studio Code 1.41.0
公式通りに普通にインストールします。
Visual Studio Code - コード エディター | Microsoft Azure5.1. AWS Toolkit for Visual Studio Code 1.4.0 / 5.2. Remote - WSL 0.41.5
vscode上のExtentionから普通にインストールします。
Installing the AWS Toolkit for Visual Studio CodeRemote - WSLはExtentionから入れなくても有効になるようです。(私はExtentionから自前で入れました。)
VSCodeのRemote WSLでWSLを快適に使う6. SAM localでHello World
ここまで来たらSAM localでPythonなlambda関数を動かせるはずです。
このページの「特徴」→「迅速に使用を開始する方法」にあるイメージのようにコマンドパレットからPython3.7のアプリケーションを作成してください。
https://aws.amazon.com/jp/visualstudiocode/作成できたら、サイドメニューのファイルのアイコン(explorer)で表示されるツリーから「app.py」を選択してエディタで表示した後にサイドバーの「AWS」のアイコンを選択します。
しばらく待つと「def lambda_handler(event, context):」の上にCodeLensで「Run Locally | Debug~」と出るので「Run Locally」をクリックすればSAM localでアプリケーションが実行されます。Visual Studio CodeでSAMアプリケーション開発
今回の手順では、全てローカル実行しAWSには接続しないので「Connect to AWS...」は触らなくて良いです。
コンソールにjsonでHello Worldとレスポンスが表示されればOKです。
7. NoSQL Workbench for Amazon DynamoDB (Preview)を使う
最近、「NoSQL Workbench」でDynamoDB localの操作も可能になりましたのでこれを使ってテーブル作成や初期データを投入しました。
次のステップで使用するので適当に簡単なテーブルを作成して、初期データを1件投入しておいてください。公式からダウンロードしてインストールします。
Download NoSQL Workbench使い方の参考はこちら。
NoSQL Workbench for Amazon DynamoDB - プレビューの使用が可能になりました8. SAM localからDynamoDB localに接続してみる
「app.py」を修正してDynamoDB localのコンテナに接続してみます。
テーブル名やPKのカラム名や値は前項で作成した自身のものを使用してください。app.py# ~中略~ import os import logging logger = logging.getLogger() logger.setLevel(logging.INFO) import boto3 def lambda_handler(event, context): # ~中略~ # SAM local上の環境変数を見る logger.info('## ENVIRONMENT VARIABLES') logger.info(os.environ) # 実行時のリクエストを見る logger.info('## EVENT') logger.info(event) # ~中略~ # dockerコンテナなSAM localからだとlocalhostでつながらない。 # SAM_DOCKER_NETWORKでdynamodb localと同じネットワークでSAM localのコンテナを動くよう指定し、dyanmodb localのコンテナ名と”コンテナ内のポート”番号をendpoint_urlに指定する。 dynamodb = boto3.resource('dynamodb', endpoint_url="http://dynamodb-local:8000") pk = {'YOUR KEY': 'KEY VALUE'} table = dynamodb.Table('YOURTABLE NAME') res = table.get_item(Key = pk) print(res) # ~中略~上手く動けば前項で設定した初期データがjson形式で表示されるはずです。
雑感
とりあえずクローズドネットワーク環境でlambda + dynamodbの開発が出来そうな目途が立ちました。
ただ、boto3.resource()のendpoint_url指定はデプロイしたら不要になるようなので、一工夫必要になると思ってます。
- 投稿日:2019-12-18T18:48:06+09:00
リアルタイム共同編集ツール『HackMD』をオンプレ運用して、好きな機能を追加して幸せになった話
はじめに
最近、ふと自分の寝顔が気になるので録画して観てみたのですが、
顎が完全に無くなっており完全にピピ美ちゃん状態になっていた @k-waragai です。
痩せようと決意した12月でした。さて、みなさんは仕事中に作業ログなどを残していますか?
自分は言語化することで見落としが無いことを確認したり他の人へ共有する目的としてメモをしています。
実装する中で分かった事実や背景、バグなどをメモとしてまとめながら進めることで
PR 作成時の Description を作る際にも役に立ち時短にも繋がっています。
ペッって貼り付けるだけで済んだりするので楽メモツールとして有名なものを上げると
あたりを使っている人が多いのではないでしょうか?
その中でも今回は 『 HackMD 』 に目を付けて
オンプレ運用してみたら好きな機能を追加出来て幸せになった話を書いていこうかなと思います。
(全面的に「HackMD」最高だからみんな使おうぜっていう記事です)なぜHackMDがいいの?比較してみた
メモツールとして有名なものを比較してみると DocBase と HackMD がいい感じということが分かりました。
※ あくまで個人的な感想を元にまとめています
サービス名 共同編集 画像upload マークダウン メモ単位のロール制限機能 料金 個人的な好み Evernote × △ △ - ベーシック: 無料
プラス: 年額3,100円× HackMD ◯ ◯ ◯ ◯ 個人利用: 無料
エンタープライズ: 要相談
(人数にもよりますが1人500円程)Love Qiita Team × ◯ ◯ △ Micro: 月額1,520円
Extra: 月額15,300円△ DocBase ◯ ◯ ◯ ◯ スターター: 月額900円
プレミアム: 月額19,500円△ 個人的に ドキュメントとして利用するには、Qiita Team もしくは DocBase がいいとは思うのですが作業メモ程度で使う分にはオーバースペックでした。
重要なドキュメントと混じってしまうのであまり良くありませんでした。DocBaseであれば Private というロール設定があるので自分のメモ板用に1つドキュメントを作ってという使い方をしていました。
ただ、めんどくさがりの自分は保存ボタンを押すのですら 面倒くさい ので長くは続きませんでした。
(最終的に Atom でメモ取ってました)そこでいろいろ試した中で良かったのが『 HackMD 』でした。
HackMDはリアルタイム共同編集が可能で保存ボタンとかは特になく 常に保存 されます。
また PDF や Slide などへもエクスポートできます。
自分だけが見れるPrivateや他者の編集を不可能にするLockedなど5種類の設定が行なえます。HackMD と CodiMD についての概要説明
HackMD は リアルタイムマークダウン共同編集ツール として 無料 で提供されております。
また HackMD にはオープンソースバージョンがあり CodiMD というものがあります。
? hackmdio/codimd: CodiMD - Realtime collaborative markdown notes on all platforms.
CodiMD では HackMD の大部分の機能を オープンソースとして提供 しており
これらをクローンするだけで簡単に手元でHackMDを動かす事が可能です。ライセンスも AGPL となっています。
素晴らしいな、おい...。。。
しかも、ここ最近でドキュメントの整備などもしっかりと行われており充実してきています。
? CodiMD Documentation - HackMDさらにさらに!
Heroku へのワンクリック構築ボタンがあったり、
? https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-heroku-deploymentk8s helm が用意されていたり、
? https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-kubernetes-deploymentDocker Image が用意されていたり、
? https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-docker-deployment多方面へのカバーも充実しているので CodiMD 様様って感じです٩(๑`ω´๑)۶
まずは clone してみよう
node は
Node.js 8.x LTS up to 11.x.
となっているようです。
(なので 8以上12以下にしてねって事らしい)余談ですが、自分が1年ほど前にやった時は node 6系 以上は保証しないよ!と言ってたはずなのに
気づいたらバージョン対応しているので結構メンテされてますね(ㆁωㆁ*) 控えめに言って最高か
ローカル開発用にDockerとかも自分で構築した良い思い出...MacOS$ git clone https://github.com/hackmdio/codimd.git $ cd codimd環境変数や設定ファイルを眺めて必要な情報をまとめてみた
環境変数についてはこちらを見ると良いです。
本番運用で最低限設定すべき項目は以下の通り
config.json
environment example value description loglevel info 標準出力に提供されるログの種類を定義します。 domain gyokuro-team.com ドメイン名 useSSL true SSLを利用するか protocolUseSSL true SSLプロコトルを利用するか urlAddPort 80 アプリケーションのポート番号 allowAnonymousEdits false 匿名ユーザーの編集を可能にするか defaultPermission private デフォルトのPermissionの設定
- freely: 誰でも閲覧編集可能
- editable: サインインしていれば閲覧編集可能
- limited: ゲスト以外は閲覧編集可能
- locked: オーナのみ編集可能
- protected: ゲスト以外のオーナのみ
- private: オーナのみしか閲覧編集はできないallowEmailRegister false Eメールでの登録を可能にするか false Eメールでのサインインを許可するか allowGravatar true アバターを利用するか sslKeyPath ./cert/privkey.pem SSLを使用する際にprivkeyの場所を指定 sslCertPath ./cert/cert.pem SSLを使用する際にcertの場所を指定 dhParamPath ./cert/fullchain.pem SSLを使用する際にFullChainの場所を指定 sslCAPath ./certchain.pem/ SSLを使用する際にCAの場所を指定 imageuploadtype s3 アップロードの際の画像の置き場
- imgur
- s3
- minio
- azure
- filesystemgithub {clientID: "x", clientSecret: "x"} githubでの登録を可能にする場合 s3bucket hackmd-bucket s3でのアップロードを指定した場合 db いろいろ dbの設定情報 環境変数
environment example value description NODE_ENV production 環境状況 HMD_IMAGE_UPLOAD_TYPE s3 画像のアップロード方法 CMD_DOMAIN production ドメイン名 CMD_URL_ADDPORT production ポート番号 HMD_DB_URL 例: mysql://hackmd:hackmdpass@127.0.0.1:3306/hackmd mysqlやpostgresqlのurlを置く ローカルで動かしてみよう(Docker)
ドキュメントにもありますが codimd 用の image が配布されています。
image: nabo.codimd.dev/hackmdio/hackmd:1.4.0
? Docker Deploymentただし今回はそれを使いません。
理由としては、自分が過去にやっていた時は node 6.x系 になっており
当時 11.x系 が最新であったことから、どうしても11.x系にしたく 必要最小限構成で自作 したのでそれで紹介します。Step1. docker-compose.yml の作成
MacOS$ touch docker-compose.ymldocker-compose.ymlversion: '3' services: # MySQL database: image: mariadb:10.4.4 container_name: hackmd_mysql environment: MYSQL_USER: "${MYSQL_USER:-hackmd}" MYSQL_PASSWORD: "${MYSQL_PASSWORD:-hackmdpass}" MYSQL_DATABASE: "${MYSQL_DATABASE:-hackmd}" MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:-rootpassword}" volumes: - database:/var/lib/mysql - ./provisioning/resources/utf8mb4.cnf:/etc/mysql/conf.d/utf8mb4.cnf restart: always ports: - "${MYSQL_USE_PORT:-3306}:3306" networks: - app-net # Node.js app: build: context: . dockerfile: ./provisioning/Dockerfile container_name: hackmd_app tty: true volumes: - .:/app - /app/node_modules working_dir: /app env_file: - ./provisioning/docker-env restart: always depends_on: - database ports: - "${APP_USE_PORT:-3000}:3000" networks: - app-net networks: app-net: driver: bridge volumes: database:Step2. Dcokerfile などを作成
MacOS$ mkdir -p provisioning/resources $ touch provisioning/Dockerfile $ touch provisioning/resources/utf8mb4.cnf $ touch provisioning/docker-env $ touch provisioning/resources/docker-entrypoint.sh
- Dockerfile
provisioning/DockerfileFROM node:11.14.0-stretch ENV DEBCONF_NOWARNINGS=yes # Set some default config variables ENV DOCKERIZE_VERSION=v0.6.1 RUN wget https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-linux-amd64-${DOCKERIZE_VERSION}.tar.gz && \ tar -C /usr/local/bin -xzvf dockerize-linux-amd64-${DOCKERIZE_VERSION}.tar.gz && \ rm dockerize-linux-amd64-${DOCKERIZE_VERSION}.tar.gz RUN mkdir /app WORKDIR /app COPY . /app # update RUN apt-get update # install RUN apt-get install -y build-essential vim RUN yarn install && \ yarn global add webpack && \ npm run build EXPOSE 3000 COPY ./provisioning/resources/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] CMD ["node", "app.js"]
- utf8mb4.cnf
provisioning/resources/utf8mb4.cnf# MariaDB-specific config file. # Read by /etc/mysql/my.cnf [client] default-character-set=utf8mb4 [mysql] default-character-set=utf8mb4 [mysqld] collation-server=utf8mb4_general_ci init-connect='SET NAMES utf8mb4' character-set-server=utf8mb4 # Import all .cnf files from configuration directory !includedir /etc/mysql/mariadb.conf.d/
- docker-env
.envrc# dockerで動かすのはdevelopment前提です。 NODE_ENV=development CMD_CONFIG_FILE=config.json DEBUG=true CMD_LOGLEVEL=info CMD_PROTOCOL_USESSL=false CMD_URL_ADDPORT=false CMD_USECDN=true CMD_ALLOW_ANONYMOUS=false CMD_ALLOW_ANONYMOUS_EDITS=false CMD_ALLOW_FREEURL=false CMD_DEFAULT_PERMISSION=limited CMD_EMAIL=false CMD_ALLOW_PDF_EXPORT=true CMD_ALLOW_EMAIL_REGISTER=false CMD_ALLOW_GRAVATAR=true CMD_IMAGE_UPLOAD_TYPE=filesystem # Change Require CMD_DB_URL=mysql://hackmd:hackmdpass@database:3306/hackmd # Githubログイン使いたいなら # CMD_GITHUB_CLIENTID={YOUR_GITHUB_CLIENT_ID} # CMD_GITHUB_CLIENTSECRET={YOUR_GITHUB_SECRET_KEY} # option: Docker Environment # MYSQL_USER= # MYSQL_PASSWORD= # MYSQL_DATABASE= # MYSQL_ROOT_PASSWORD= # APP_USE_PORT=
- docker-entrypoint.sh
provisioning/resources/docker-entrypoint.sh#!/usr/bin/env bash dockerize -wait tcp://database:3306 -timeout 30s node_modules/.bin/sequelize db:migrate exec "$@"Step3. configファイル等を整える
MacOS$ cp config.json.example config.json $ cp .sequelizerc.example .sequelizerc
- config.json
一旦、SAML とか 画像S3に上げるととかは一旦考えず最小限で行う。
ログインは Githubログイン で行いたいが後で変更するためここでは行わない。
config.json{ "development": { "useSSL": false, "tmpPath": "./tmp/", "defaultNotePath": "./public/default.md", "docsPath": "./public/docs", "viewPath": "./public/views", "uploadsPath": "./public/uploads" } }Step4. docker up してみよう
MacOS$ docker-compose up -dこれで
localhost:3000
にアクセスすれば見れるので
ローカルでの開発が捗る٩(๑`ω´๑)۶※ もし アクセス後 ビルドエラーのような画面が出た場合は以下をお試しください。
$ docker-compose run --rm app npm run build $ docker-compose run --rm yarn installStep5. タイトルを変えてみよう
public/views/index/body.ejs
の 43行目付近にある以下を修正- <h1 class="cover-heading"><i class="fa fa-file-text"></i> CodiMD</h1> + <h1 class="cover-heading"><i class="fa fa-file-text"></i> k-waragaiMD</h1>
これでやる気UP (´∀`∩)↑age↑
Step6. Githubログインを出来るようにしてみよう
? https://github.com/settings/developers にアクセスを行い
New OAuth App
をクリック必要な情報を入力して
Register application
をクリック
ClientID
とSecretKey
が吐き出されるのでそれをメモします。一度
docker-compose down
を行います。docker-env を編集してください。
docker-env... # Change Require CMD_DB_URL=mysql://hackmd:hackmdpass@database:3306/hackmd # Githubログイン使いたいなら - # CMD_GITHUB_CLIENTID={YOUR_GITHUB_CLIENT_ID} - # CMD_GITHUB_CLIENTSECRET={YOUR_GITHUB_SECRET_KEY} + CMD_GITHUB_CLIENTID=SampeClientIdDesu + CMD_GITHUB_CLIENTSECRET=SampeSecretKeyDesu # option: Docker Environment # MYSQL_USER= # MYSQL_PASSWORD= # MYSQL_DATABASE= # MYSQL_ROOT_PASSWORD= # APP_USE_PORT=編集が完了したら
docker-compose up -d
をすると
先程は無かったサインイン
のボタンが現れるようになります。試しにログインをすると、Githubからユーザー名などを取れておりログインできてる事がわかります。
EC2で動かしてみよう(ホスト)
Ubuntu でざっくりと docker を使用せずに構築したいと思います。
基本的なセキュリティの設定などは各々あると思いますので省かせていただきます。すでにEC2にsshしている状態でのお話になります。
Step1. 事前準備
- apt update upgrade
EC2インスタンス[ubuntuユーザー]$ sudo apt update $ sudo apt upgradeStep2. ユーザーの作成とsudoグループ追加
EC2インスタンス[ubuntuユーザー]# ユーザーの作成 $ sudo adduser hackmd Adding user `hackmd' ... Adding new group `hackmd' (1001) ... Adding new user `hackmd' (1001) with group `hackmd' ... Creating home directory `/home/hackmd' ... Copying files from `/etc/skel' ... Enter new UNIX password: passwordを入力... Retype new UNIX password: passwordを入力... passwd: password updated successfully Changing the user information for hackmd Enter the new value, or press ENTER for the default Full Name []: Room Number []: Work Phone []: Home Phone []: Other []: # sudo グループへ hackmd ユーザーを追加 $ sudo gpasswd -a hackmd sudo # スイッチッ!!!!!! $ sudo su - hackmdStep3. 必要なパッケージのインストール
- コアになりそうなもののインストール
EC2インスタンス[hackmdユーザー][hackmd]$ sudo apt-get install -y git build-essential wget vim unzip libssl-dev python
- nvm のインストール
EC2インスタンス[hackmdユーザー][hackmd]$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.35.0/install.sh | bash [hackmd]$ export NVM_DIR="$HOME/.nvm" [hackmd]$ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" [hackmd]$ [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" [hackmd]$ source ~/.bashrc [hackmd]$ nvm --version 0.35.0
- node のインストール
EC2インスタンス[hackmdユーザー][hackmd]$ nvm install v11.14.0 [hackmd]$ nvm use v11.14.0 [hackmd]$ node -v 11.14.0
- yarn のインストール
EC2インスタンス[hackmdユーザー][hackmd]$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - [hackmd]$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list [hackmd]$ sudo apt-get update && sudo apt-get -y install yarn [hackmd]$ export PATH="$PATH:/opt/yarn-1.15.2/bin" [hackmd]$ source ~/.bashrc [hackmd]$ yarn -v 1.15.2
- mariaDBインストール(MySQLでも良い)
EC2インスタンス[hackmdユーザー][hackmd]$ curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash [hackmd]$ sudo apt -y update [hackmd]$ apt install -y mariadb-server-10.3 [hackmd]$ mysql_secure_installation Enter current password for root (enter for none): > パスワード Change the root password? [Y/n] > Y > New password: パスワード > Re-enter new password: パスワード Remove anonymous users? [Y/n] > n Disallow root login remotely? [Y/n] > Y Remove test database and access to it? [Y/n] > Y Reload privilege tables now? [Y/n] > Y [hackmd]$ mysql -uroot -p -h 127.0.0.1 -e "show databases;" > ルートパスワード +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | +--------------------+ # ユーザー作成 [hackmd]$ mysql -uroot -p -h 127.0.0.1 -e "CREATE USER ユーザー名 IDENTIFIED BY 'パスワード';" # 権限付与 [hackmd]$ mysql -uroot -p -h 127.0.0.1 -e "GRANT ALL ON *.* TO 'ユーザー名'@'localhost' IDENTIFIED BY 'パスワード';" # 適用 [hackmd]$ mysql -uroot -p -h 127.0.0.1 -e "FLUSH PRIVILEGES;" [hackmd]$ mysql -uユーザー名 -p -h 127.0.0.1 -e "create database データベース名;"
- nginx
EC2インスタンス[hackmdユーザー][hackmd]$ curl http://nginx.org/keys/nginx_signing.key | sudo apt-key add - [hackmd]$ VCNAME=`cat /etc/lsb-release | grep DISTRIB_CODENAME | cut -d= -f2` && sudo -E sh -c "echo \"deb http://nginx.org/packages/ubuntu/ $VCNAME nginx\" >> /etc/apt/sources.list" [hackmd]$ VCNAME=`cat /etc/lsb-release | grep DISTRIB_CODENAME | cut -d= -f2` && sudo -E sh -c "echo \"deb-src http://nginx.org/packages/ubuntu/ $VCNAME nginx\" >> /etc/apt/sources.list" [hackmd]$ sudo apt-get update [hackmd]$ sudo apt-get install -y nginxStep4. リポジトリのクローンと設定
github の
.netrc
などの設定は一旦省かせていただきます。
また config.json や sequelizerc はローカルのときとほとんど同じとなっていますのでSKIPしていただいても構いません。
ただ、SSLの関係上環境変数などが若干増えています。EC2インスタンス[hackmdユーザー][hackmd]$ git clone https://github.com/hackmdio/codimd.git [hackmd]$ cd codimd [hackmd]$ cp .sequelizerc.example .sequelizerc [hackmd]$ cp config.json.example config.json
- utf8mb4.cnf の設定
EC2インスタンス[hackmdユーザー][hackmd]$ sudo vim /etc/mysql/mariadb.conf.d/utf8mb4.cnf/etc/mysql/mariadb.conf.d/utf8mb4.cnf# MariaDB-specific config file. # Read by /etc/mysql/my.cnf [client] default-character-set=utf8mb4 [mysql] default-character-set=utf8mb4 [mysqld] collation-server=utf8mb4_general_ci init-connect='SET NAMES utf8mb4' character-set-server=utf8mb4 # Import all .cnf files from configuration directory !includedir /etc/mysql/mariadb.conf.d/
config.json の設定
画像は S3 へ アップロード
ログインは メール登録を禁止しGithubログインのみ
ゲストユーザーは書き込み閲覧を出来ない
ドメインの指定
という形でconfigを作っていきます。
SSLはこの段階では行わないが後述で行います。
Github の
EC2インスタンス[hackmdユーザー][hackmd]$ vim config.jsonconfig.json{ "production": { "loglevel": "info", "useSSL": false, "protocolUseSSL": false, "domain": "xxxxxxxxxxx.com", #--ドメインがあるのであれば "urlAddPort": "80", "allowAnonymousEdits": false, "defaultPermission": "private", "allowEmailRegister": false, "email": false, "allowGravatar": true, "db": { "username": "xxxxxxxxxxx", "password": "xxxxxxxxxxx", "database": "xxxxxxxxxxx", "host": "127.0.0.1", "port": "3306", "dialect": "mysql" }, "github": { "clientID": "xxxxxxxxxxxxxxxxxxxxxx", "clientSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, "imageuploadtype": "s3", "s3": { "accessKeyId": "xxxxxxxxxxxxxxxxxxxxxx", "secretAccessKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "region": "ap-northeast-1" }, "s3bucket": "codimd-production" } }
- nginx の設定
EC2インスタンス[hackmdユーザー][hackmd]$ sudo vim /etc/nginx/conf.d/node-app.conf/etc/nginx/conf.d/node-app.confserver { listen 80; # listen 443 ssl; ssl on; # 編集すること server_name {YOUR_DOMAIN}.com; # 今はまだ使わない # ssl_certificate /etc/letsencrypt/live/{YOUR_DOMAIN}.com/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/{YOUR_DOMAIN}.com/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { proxy_pass https://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } # あとで SSL取得に使う location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; root /home/hackmd/codimd/public; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /home/hackmd/codimd/public; } }EC2インスタンス[hackmdユーザー][hackmd]$ sudo systemctl restart nginx
- 無料枠だとRAMに限界あるので SWAP領域を作成
EC2インスタンス[hackmdユーザー][hackmd]$ sudo dd if=/dev/zero of=/swap bs=1M count=1024 [hackmd]$ sudo mkswap /swap [hackmd]$ sudo swapon /swap [hackmd]$ sudo chmod 600 /swapStep5. 立ち上げ
EC2インスタンス[hackmdユーザー][hackmd:~/codimd]$ yarn install [hackmd:~/codimd]$ yarn global add webpack [hackmd:~/codimd]$ npm run build [hackmd:~/codimd]$ node_modules/.bin/sequelize db:migrate [hackmd:~/codimd]$ node app.jsStep6. 永続的にappを立ち上げさせる
EC2インスタンス[hackmdユーザー][hackmd:~/codimd]$ npm install -g forever [hackmd:~/codimd]$ forever start app.jsStep7. SSL化(HTTPS)
今回は
Let's Encrypt
を利用します
- certbot challenge
EC2インスタンス[hackmdユーザー][hackmd:~/codimd]$ mkdir -p .well-known/acme-challenge/ [hackmd:~/codimd]$ chmod 644 .well-known/acme-challenge/ [hackmd:~/codimd]$ cd ~/ [hackmd:~/]$ git clone https://github.com/certbot/certbot.git && cd certbot [hackmd:~/]$ sudo ./certbot-auto certonly --webroot -w /home/hackmd/codimd/public -d {YOUR_DOMAIN}.com -m {YOUR_MAIL_ADDR} --debug
- application側の対応
EC2インスタンス[hackmdユーザー][hackmd:~/]$ cd codimd
- 環境変数の変更
EC2インスタンス[hackmdユーザー][hackmd:~/codimd]$ direnv edit ..ervrc- export CMD_PROTOCOL_USESSL=false + export CMD_PROTOCOL_USESSL=true
- config.json の変更
EC2インスタンス[hackmdユーザー][hackmd:~/codimd]$ vim config.jsonconfig.json{ "production": { "loglevel": "info", - "useSSL": false, - "protocolUseSSL": false, + "useSSL": true, + "protocolUseSSL": true, + "sslKeyPath": "/etc/letsencrypt/live/xxxxxxxxxxx.com/privkey.pem", + "sslCertPath": "/etc/letsencrypt/live/xxxxxxxxxxx.com/cert.pem", + "dhParamPath": "/etc/letsencrypt/live/xxxxxxxxxxx.com/fullchain.pem", + "sslCAPath": ["/etc/letsencrypt/live/xxxxxxxxxxx.com/chain.pem"], "domain": "xxxxxxxxxxx.com", #--ドメインがあるのであれば "urlAddPort": "80", "allowAnonymousEdits": false, "defaultPermission": "private", "allowEmailRegister": false, "email": false, "allowGravatar": true, "db": { "username": "xxxxxxxxxxx", "password": "xxxxxxxxxxx", "database": "xxxxxxxxxxx", "host": "127.0.0.1", "port": "3306", "dialect": "mysql" }, "github": { "clientID": "xxxxxxxxxxxxxxxxxxxxxx", "clientSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, "imageuploadtype": "s3", "s3": { "accessKeyId": "xxxxxxxxxxxxxxxxxxxxxx", "secretAccessKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "region": "ap-northeast-1" }, "s3bucket": "codimd-production" } }
- nginx の変更
EC2インスタンス[hackmdユーザー][hackmd:~/codimd]$ sudo vim /etc/nginx/conf.d/node-app.conf/etc/nginx/conf.d/node-app.confupstream node-app { server localhost:3000; } server { listen 443 ssl; ssl on; server_name xxxxxxxxxxxx.com; ssl_certificate /etc/letsencrypt/live/xxxxxxxxxxx.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/xxxxxxxxxxx.com/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { proxy_pass http://node-app/; } location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; root /home/hackmd/codimd/public; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /home/hackmd/codimd/public; } }EC2インスタンス[hackmdユーザー][hackmd:~/codimd]$ sudo systemctl restart nginxStep8. Restart
EC2インスタンス[hackmdユーザー][hackmd:~/codimd]$ forever app.js restartアクセス!
Github の
New OAuth App
はSSLが出来たタイミング等で先程と同じ手順で行ってください。ちゃんと鍵も出てるし ログインも出来る〜。 \ 最 高 /
トラブルシューティング
- SSL化にて challenge に失敗した場合、原因として
.well-known/acme-challenge/
にアクセス出来てない可能性があります。
chmod 644 .well-known/acme-challenge/
などをしてみてください。- また、 challenge 時 80番(HTTP)でアクセスが来るはずなので 更新の際は
listen 80
にするのを忘れずに- 今回はドメインの設定を公開してないですが タイプA の設定をしています。(google で買ったドメインを利用しています。)
チームで使っている板を自動でQiita Teamに投稿できるようにしてみた
私達のチームでは、1つの板を専有し毎日更新し続けています。
その板に書いているものは以下の通りとなっております。
- 共有事項
- 有給取る日やフレックス出社日など
- 今日のゴール
- 今日終わらせるべきタスクを明確にする
- 作業ログ
- 作業を行う際、個人個人がそれぞれh2でタイトルを切ってログ等をまとめたりする
今までは翌日の朝にこれらを全コピしてQiita Teamに転記していたのですが、
まあちょっとの繰り返しさえも自動化したくなるのがエンジニア魂ですよね(ㆁωㆁ*)めんどくさいだけやり方は簡単で Qiita API を使ったスクリプトを Cron で平日毎日 22:00 頃に回すだけです。
sampleコードを載せておきます。
post_daily_report_by_cosmos_team.rbrequire 'net/https' require 'mysql2' require "json" require "date" mysql_username = ENV['MYSQL_USERNAME'].freeze mysql_password = ENV['MYSQL_PASSWORD'].freeze mysql_database = ENV['MYSQL_DATABASE'].freeze team_note_id = ENV['TEAM_NOTE_ID'].freeze qiita_api_key = ENV['QIITA_API_KEY'].freeze domain = ENV['TEAM_DOMAIN'].freeze client = Mysql2::Client.new( socket: '/var/run/mysqld/mysqld.sock', username: mysql_username, password: mysql_password, encoding: 'utf8', database: mysql_database ) statement = client.prepare('SELECT content FROM Notes WHERE id = ?') # 事前にタイトルで select しておき ID を控えています。 # example: # mysql -uhackmd -p hackmd -e "select id from Notes where title = 'cosmos開発日報'" results = statement.execute(team_note_id) weekday = ["日", "月", "火", "水", "木", "金", "土"] today = Date.today title = "cosmos開発日報" + today.strftime("%Y/%m/%d (#{weekday[today.wday]})") content = "" results.each do |row| content = row["content"] end # 組み立て qiita = "https://#{domain}.qiita.com/" path = '/api/v2/items' url = qiita + path uri = URI.parse(url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE req = Net::HTTP::Post.new(uri.request_uri) req["Authorization"] = "Bearer #{qiita_api_key}" req["Content-Type"] = "application/json" post_data = { title: title, body: content, coediting: true, group_url_name: "cosmos", private: false, tags: [{name: "cosmos"},{name: "日報"}], tweet: false, }.to_json # 投稿 req.body = post_data # 結果 res = http.request(req) puts res.code, res.msgcrontab# Edit this file to introduce tasks to be run by cron. 00 13 * * 1-5 bash -cl 'cd /home/hackmd/cron_scripts/ && ruby -Ku post_daily_report_by_cosmos_team.rb'毎日こんな感じで投稿されるようになりました! \ 自 動 化 バ ン ザ イ /
こんな感じで好きな機能を追加したりをしてみたり実験場としても活躍しています!
最後に
今回は docker で構築する方法と ホスト上に直接構築する方法の2種類を紹介いたしました!
応用すれば ECS にすることも出来ますね(ㆁωㆁ*)エンジニアとして、「あのサービスにこの機能があったら最高なんだけど...」って思うことって多々ありますよね。
もともと利用してたHackMDをそのまま改造出来るって最高だなって思いました。 THE 幸せ
HackMDはエンタープライズ版があるとお話していましたが、エンタープライズ版では高頻度で504になり 自動復旧を待つ ということが高頻度で起きました。
連続で起きるときもあれば起きないときもあり、不安定な状態が続いた為オンプレ化を進めたのが実背景となっています。実際やってみるとそこまで難しいことはなく、 機能の拡張 なども容易に行えてしばらくは遊べそうです(ㆁωㆁ*)
料金も EC2 インスタンスの無料枠(t2.micro)を使っていますが、アクティブユーザーは最大15人とかでも落ちるといったことは今までありませんでした。
画像もS3にあげているので容量圧迫とかも起きず快適に利用できています!
文字だけなのでmysql自体の負荷も少ないことから、 社内で50人くらいで使う分には無料枠で全然問題ない かと思われます。
ぜひ皆様も CodiMD を利用してみてくださいね(ㆁωㆁ*) bye
? hackmdio/codimd: CodiMD - Realtime collaborative markdown notes on all platforms.
またもっと良いツールがあるよ!って方はぜひ教えて下さい!
Twitterもやってるのでぜひフォローください。
? つなまよ(@mayoxtuna)さん / Twitter
Apex Legends(PC版)とか一緒に趣味開発してくれるお友達募集中です٩(๑`ω´๑)۶次回予告
明日は クリスマス・イブ ですね٩(๑`ω´๑)۶ ? :.。.:May your Christmas wishes come true:.。.: ?
12月24日は クラウドワークスエンジニアである @cesare による 「複業を支える技術」です!
お楽しみに〜bye2019/12/24 追記
この記事を公開したあと Twitter 経由で HackMD の CEO の方から直々に感謝のDMを頂きました。
そこで エンタープライズ版の 504 になる問題について教えていただきました。現在では高パフォーマンスで動く状態を維持しており、それらの問題は起きないとのことでした (ㆁωㆁ*)
日々進化し続ける HackMD 最高ですね٩(๑`ω´๑)۶
- 投稿日:2019-12-18T16:12:31+09:00
MySQL Workbenchに日本語CSVをインポート
よくある話
必要に迫られMySQLにAccessデータをインポートする事になり、四苦八苦した話です。ほぼ備忘録ですが、同じところで躓いている方のお役に立てれば。(類似記事は多かったけれど、中々自分のパターンにあてはまるものが無かった)
環境
・Windows10 Enterprise
・Docker Desktop for Windows:2.1.0.1
・MySQL:5.7.28
・MySQL Workbench 8.0概要
・Docker ComposeでMySQLコンテナをビルド
・MySQL WorkBenchでコンテナのDBに接続し編集
・Accessからcsvエクスポート(UTF-8)したものをMySQLにインポートインポート失敗
MySQL Workbenchのメニュー「Database」→「Migration Wizard」はちょっと面倒そうだったので、左メニューのインポートしたいデータベース名を右クリック→「Table Data Import Wizard」でインポート作業。
サクッといけると思ったけれど日本語が入っているとエラーでインポートできない。
テスト用にCSVで簡単なテーブルを作ってインポートしたが、1文字でも日本語が入っているレコードはインポートされなかった。デフォルト文字コード変更
色々調べた中で、こちら↓の記事の内容で解消。助かりました。
MySQLでcharacter_set_databaseがlatin1になってしまう問題の対応方法MySQLにログインした状態でコマンド「show variables like 'char%';」実行した際に表示される各文字コードの中で、character_set_databaseが「latin1」から変更出来ないのが原因だった。下記手順にて設定変更に成功した。
手順
1:mysqlログイン
2:コマンド「use{インポート先のDB名}
」でDB指定
3:コマンド「show variables like 'char%';」実行 → character_set_databaseが「latin1」になっている事を確認
4:コマンド「show create database `{インポート先のDB名}`;」 →/*!40100 DEFAULT CHARACTER SET latin1 */
になっている
5:「ALTER DATABASE `{インポート先のDB名}` default character set utf8;」実行し、デフォルトをUTF8に変更
6:コマンド「show variables like 'char%';」実行 → character_set_databaseが「utf8」に変更された事を確認
7:MySQL WorkBenchで日本語含むcsvのインポート成功おわりに
業務逼迫中のメモなので図も無いざっくりで申し訳ないですが、また余裕出来たらちゃんと書き直したいと思います。読んで頂いてありがとうございました。
- 投稿日:2019-12-18T16:12:31+09:00
MySQL Workbenchで日本語CSVをインポート
よくある話
必要に迫られMySQLにAccessデータをインポートする事になり、四苦八苦した話です。ほぼ備忘録ですが、同じところで躓いている方のお役に立てれば。(類似記事は多かったけれど、中々自分のパターンにあてはまるものが無かった)
環境
・Windows10 Enterprise
・Docker Desktop for Windows:2.1.0.1
・MySQL:5.7.28
・MySQL Workbench 8.0概要
・Docker ComposeでMySQLコンテナをビルド
・MySQL WorkBenchでコンテナのDBに接続し編集
・Accessからcsvエクスポート(UTF-8)したものをMySQLにインポートインポート失敗
MySQL Workbenchのメニュー「Database」→「Migration Wizard」はちょっと面倒そうだったので、左メニューのインポートしたいデータベース名を右クリック→「Table Data Import Wizard」でインポート作業。
サクッといけると思ったけれど日本語が入っているとエラーでインポートできない。
テスト用にCSVで簡単なテーブルを作ってインポートしたが、1文字でも日本語が入っているレコードはインポートされなかった。デフォルト文字コード変更
色々調べた中で、こちら↓の記事の内容で解消。助かりました。
MySQLでcharacter_set_databaseがlatin1になってしまう問題の対応方法MySQLにログインした状態でコマンド「show variables like 'char%';」実行した際に表示される各文字コードの中で、character_set_databaseが「latin1」から変更出来ないのが原因だった。下記手順にて設定変更に成功した。
手順
1:mysqlログイン
2:コマンド「use{インポート先のDB名}
」でDB指定
3:コマンド「show variables like 'char%';」実行 → character_set_databaseが「latin1」になっている事を確認
4:コマンド「show create database `{インポート先のDB名}`;」 →/*!40100 DEFAULT CHARACTER SET latin1 */
になっている
5:「ALTER DATABASE `{インポート先のDB名}` default character set utf8;」実行し、デフォルトをUTF8に変更
6:コマンド「show variables like 'char%';」実行 → character_set_databaseが「utf8」に変更された事を確認
7:MySQL WorkBenchで日本語含むcsvのインポート成功おわりに
業務逼迫中のメモなので図も無いざっくりで申し訳ないですが、また余裕出来たらちゃんと書き直したいと思います。読んで頂いてありがとうございました。
- 投稿日:2019-12-18T14:49:13+09:00
Private Docker Container Registryサービスを作った話
こんにちは、さくらインターネットのこたまごです。
今日は、今日リリースしたサービス「Sakura Container Registry」のお話をします。
Private Container Registryとは
Dockerなどのコンテナランタイムでは、実行するコンテナのイメージをどこからか取得する必要があります。
このイメージを保管する機能がContainer Registryです。最も利用されていると思われるのは Docker Hub でしょうか。NginxやPHP、PostgreSQLなど、公式、非公式問わずたくさんのイメージが共有され公開されています。
基本的にこれらのイメージは誰でもダウンロードすることができます。
一方で、自分だけがアクセスできるContainer RegistryがPrivate Container Registryです。
Docker Hubでも、有料プランを利用することで自分だけのイメージを保管することができます。昨今コンテナの利用が進む中、意外とめんどくさいのがこのリポジトリの用意と運用です。
Sakura Container Registryの使い方
さくらのクラウド ドキュメントもご参照ください。
レジストリの作成
さくらのクラウドにログインし、メニューから「コンテナレジストリ」→「作成」ボタンをクリック。
コンテナレジストリ名と公開設定が重要なポイントです。
コンテナレジストリ名は一度設定すると変更できません。公開設定はログインしていないユーザーのアクセス権を設定することができます。
- 「Push & Pull」イメージの更新も誰でもできるレジストリになります
- 「Pullのみ」イメージの更新は認証が必要ですが、イメージを取得し利用するのは誰でもできるレジストリになります
- 「非公開」イメージの更新も取得も認証が必要なレジストリになります
現時点では独自ドメインは利用できませんが、近々対応したいと思っています。
コンテナレジストリ名を決めて作成すると「example.sakuracr.jp」のようなドメインが割り当てられます。これは後から変更できません。
ユーザーの作成
実際に使う前にユーザーの追加が必要です。「ユーザー」タブから追加と削除ができるので追加してください。
現時点では読み書き (Push & Pullどちらもできる) 権限のあるユーザーしか作成できませんが、今後読み込み (Pull) 専用ユーザーも用意しようと思います。
Dockerから使う
まずログインをしておく必要があります。
$ docker login example.sakuracr.jp Username: (作ったユーザーのユーザー名) Password: (パスワード)
Login Succeeded
と表示されればOKです。次に、アップロード(push)したいイメージを作成します。イメージ名は必ず
example.sakruacr.jp/(好きな名前):(タグ)
としてください。ex)
example.sakuracr.jp/nginx:latest
,example.sakuracr.jp/awsomeproject/application:latest
今回は例としてNginxのイメージをそのまま利用します。
$ docker pull nginx:latest $ docker tag nginx:latest example.sakuracr.jp/nginx:latest
Dockerfile
がある場合には$ docker build -t example.sakuracr.jp/awsomeproject/application:latestなどとしましょう。
あとはpushするだけです。
$ docker push example.sakuracr.jp/nginx:latest
or
$ docker push example.sakuracr.jp/awsomeproject/application:latest
サービスの仕組み
Docker Distributionをベースに、マルチテナントなContainer Registryを開発しました。
- 認証管理システム
- Container Registry
- ストレージ
- キャッシュ
の4つのアプリケーションで構成されています。
認証管理システム
どんなレジストリがあるか、どんなユーザーがあるかを管理しています。
また、実際の認証認可も行っており、docker login
コマンド等の要求に対してJWT (JSON Web Tokens) で署名された認証キーの発行をしています。私の趣味によりPythonとDjangoで書かれています。
Container Registry
docker push
docker pull
コマンドで実際に通信するサーバです。HTTPSのみに対応しており、SNIによってホスト名を識別後、ホスト名に応じて挙動が変わるようになっています。
これ自身にはパスワード認証の機能はなく、全て上記の認証管理システムから発行されたJWTによって認証認可を行っています。Goで書かれています。
ストレージ
docker push
されたイメージを全て保存しているストレージです。社内の分散ストレージを利用しています。キャッシュ
docker pull
が実行されたとき、イメージによってはかなり大きなデータ量の読み出しと送信が発生します。
また、Container Registryの特性上、分散したRegistryサーバに対して同じイメージが並列でリクエストされることが想定されます。そこで、Container Registryとストレージの間にキャッシュサーバを挟み、イメージのキャッシュを行っています。
ハッシュ値によってキャッシュするサーバを決定することで、多数あるContainer Registryからの同じデータへのアクセスが一箇所のキャッシュサーバに集中するような工夫をしています。
Goで書かれています。
さいごに
本サービスは、さくらインターネット内に新たにできたチーム「エンジニアリングラボ」で開発されたサービスです。
エンジニアリングラボでは品質に固執せず、開発早期の段階でお客様にご提供し、使ってみていただけるような取組を行うことを目的としております。これからもさくらのエンジニアリングラボでは様々なサービスをお届けしていきます。
うまくいけばそのまま本番サービスとして提供できるものもあれば、お試し提供中に終了となるサービスも生まれるかもしれません。
ワクワクするようなたくさんの体験を皆さんに提供できるように努力していきますので、どうぞよろしくお願いいたします。できるまで
「開発早期の段階でお客様にご提供する」精神で、開発開始から17日でリリース!
- 12/2 レジストリが欲しいと弊社社員が言う
- 12/6 調査開始
- 12/7 レジストリ実装
- 12/8 管理システム実装
- 12/9 コンパネ実装
- 12/19 本番環境APIリリース
- 12/23 本番環境コンパネリリース
- 投稿日:2019-12-18T13:43:07+09:00
Docker開発環境のDBにReadOnlyユーザーを作り、書き込みバグを検知する
この記事は、Docker Advent Calendar 2019の19日目の記事です。
TL;DR
- Dockerを開発環境で使う際に、replica databaseを使うようなアプリケーションにて、書き込みバグを検知する
- MySQLのデータベースにreadOnlyユーザーを作成してアプリケーションから利用する
- レプリカラグの考慮などには対応できないが、最低限書き込みバグを防ぐことができる
ReadOnlyユーザーを作る
Webアプリケーション開発において、PostgreSQLやMySQLといったRDBMSをシステムのデータベースとして使うケースは多いです。そのような構成において、負荷対策で参照クエリを逃がすと行った用途でReplicaインスタンス(読み込み専用)を用意することは多いでしょう。
このシステム構成で、Docker開発環境を作る場合、データベースサービスをローカルのDockerコンテナとして立てる際、間違えてReplicaデータベースに書き込むバグ作っちゃったとはならないようにしたいですよね。この目的感のもと採用できる打ち手の一つが、ReadOnlyユーザーを作成する方法です。
この方法は、すぐに実践できる手軽さもあり、それなりの数の実践事例を観測しています。たとえば、CakeFest 2019というCakePHPの国際カンファレンスでの「Working with Database Replications in CakePHP」という発表の中でも、レプリカデータベースに対して書き込んでしまうようなアプリケーションバグを検知するために、ReadOnlyユーザーを作成するという話をしていました。
実際に、筆者の現場でも同様の方法を採用しています。この方法はレプリケーションラグの考慮などを踏まえると完全なシミュレーション方法ではありませんが、初手としては良い方法と考えています。
実現例
今回実現する例は、次のような構成です。
- MySQLを利用、MySQLのimageは公式のものを利用します
- 複数コンテナサービスが必要なため docker-compose を用います
例題として取り上げるものは下記のGitHub repositoryに公開しています。
https://github.com/hgsgtk/health-endpoint
├── docker-compose.yml ├── docker │ └── db │ ├── conf.d │ │ └── custom_my.cnf │ └── docker-entrypoint-initdb.d │ ├── 1_initialize_tables.sql │ └── 2_readuser.sql └── src └── Dockerfiledocker-compose.yml
早速、docker-compose.ymlを見てみましょう。Compose file formatはversion 3を用いています。
refs: https://docs.docker.com/compose/compose-file/
docker-compose.ymlversion: '3' services: health-api: build: context: "./src/" ports: - "8080:8080" depends_on: - db restart: on-failure env_file: - ".env" db: image: mysql:5.6 ports: - "3306:3306" expose: - 3306 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: healthy MYSQL_USER: wruser MYSQL_PASSWORD: password volumes: - ./docker/db/data:/var/lib/mysql:cached - ./docker/db/conf.d:/etc/mysql/conf.d:cached - ./docker/db/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d:cached話を単純にするために2つのサービスのみを取り上げます。Web APIである
heath-api
とMySQLデータベースであるdb
を定義しています。mysql公式イメージの使い方のおさらい
環境変数
mysql
の公式イメージの使い方をざっとおさらいすると、MYSQL_ROOT_PASSWORD
など特定の環境変数を指定することで作成されるrootユーザーのパスワードなどを指定することが出来ます。https://hub.docker.com/_/mysql の
Environment Variables
を見ることで環境変数で設定できる項目を確認することが出来ます。データの永続化
コンテナが停止したときにデータが消えてしまうと開発環境としては少し物足りませんね。データをコンテナ停止しても永続化された状態にするために、次の記述でボリュームマウントします。
docker-compose.ymlvolumes: - ./docker/db/data:/var/lib/mysql:cachedこれは、 https://hub.docker.com/_/mysql の
Caveats > Where to Store Data
に説明されています。Git管理下におくとMySQLのデータがそのままコミットされてしまうので、対象ディレクトリを.gitignore
に追加しておくのを忘れないようにしましょう。.gitignore# docker database local mount files docker/db/dataCustom MySQL Configuration
デフォルトの設定ではなく、ユーザー自身でMySQLの設定をカスタムしたいという場合は、コンテナ内の
/etc/mysql/conf.d
に設定をマウントします。これは、 https://hub.docker.com/_/mysql のUsing a custom MySQL configuration file
に説明されています。docker-compose.ymlvolumes: - ./docker/db/conf.d:/etc/mysql/conf.d:cached例えば、このケースではつぎのような
my.cnf
を設定します。docker/db/cnf.d/custom_my.cnf[mysqld] explicit_defaults_for_timestamp=1 symbolic-links=0 sql_mode=TRADITIONAL,NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY character-set-server=utf8 [client] default-character-set=utf8ReadOnlyユーザーを設定する
ReadOnlyユーザーを設定します。
docker-compose.yml
では次の設定項目が該当します。docker-compose.ymlvolumes: - ./docker/db/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d:cachedまずは、
docker-entrypoint-initdb.d
についてですが、コンテナ内の/docker-entrypoint-initdb.d
に.sh
・.sql
・.sql.gz
拡張子のファイルをおくと、初期化の実行してくれます。そのため、この初期化時にReadOnlyユーザーを作るSQLを実行すれば、ReadOnlyユーザーを作成できます。
docker/db/docker-entrypoint-initdb.d/2_readuser.sqlGRANT SELECT, PROCESS ON *.* TO 'reader'@'%' IDENTIFIED BY 'password';ファイル名ですが、
Files will be executed in alphabetical order.
という記述が、https://hub.docker.com/_/mysql の
Initializing a fresh instance
にあることが理由です。アルファベット順にソートされ実行されるので、明示的に順番になるように数字を先頭にしています。実際にReadOnlyユーザーが作れているか
実際に、rootアカウントでデータベースにアクセスし、ユーザーが作られているか確認します。
mysql.user
テーブルに対して検索すると次のような結果が得られます。SELECT User FROM mysql.user;reader root wruser root作成したReadOnlyユーザーである
reader
を確認することが出来ます。このユーザーには、GRANT
で権限を付けているので、SELECT
とPROCESS
が可能なユーザーになっています。SELECT User, Select_priv, Insert_priv, Update_priv, Delete_priv, Process_priv FROM mysql.user WHERE User = 'reader';reader Y N N N Yこれで、このデータベースを使うコンテナサービスが、レプリカ接続にReadOnlyユーザーを使うことで、誤って書き込みがおこなれても無事失敗するようになります。
ReadOnlyユーザーで書き込みをした場合INSERT INTO customers VALUES (1, now(), now())INSERT command denied to user 'reader'@'172.27.0.1' for table 'customers'余談: test_データベース
MySQL、とくに5.6の挙動に詳しい方であれば、ReadOnlyユーザーと聞いたときに、「テスト用データベースの場合の考慮はいらないだろうか」と疑問に思うかもしれません。MySQL 5.6の挙動として、次のような仕様があります。
さらに、mysql.db テーブルにはすべてのアカウントが test データベースおよび test_ で始まる名前を持つその他のデータベースにアクセスすることを許可する行が含まれます。これは、デフォルトの匿名アカウントのように、そうでなければ特別な権限を持たないアカウントにも当てはまります。
https://dev.mysql.com/doc/refman/5.6/ja/default-privileges.html
この仕様のままであれば、
test
あるいはtest_
で始まるデータベースの場合、ReadOnlyユーザーの権限を作っても書き込めてしまうことになります。これに対して、MySQL管理者への推奨は、データベースへのアクセスを、その目的のために明示的に許可を付与されたアカウントのみに制限する場合は、管理者は mysql.db テーブルのこれらの行を削除するとよいでしょう。
とある通り、mysql.dbテーブルから該当行を削除することでこの挙動を無効にする対応が必要と説明しています。
これは、MySQLの公式イメージでは実際意識する必要はありません。なぜなら、イメージの
docker-entrypoint.sh
にて、該当行の削除をしてくれているからです。DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' ;公式イメージを使用すると、このようなコミュニティのナレッジを対応してくれているものを利用できるのが利点ですね。
最後に
ReadOnlyユーザーを作る方法は、比較的手軽に実践できるので、まだやっていない方は、一つの選択肢として検討してみてはいかがでしょうか。
- 投稿日:2019-12-18T13:22:10+09:00
wordpressの環境で2MBの制限をうける!(docker編)
あんまりこの編詳しくないので忘れないように覚書。
https://qiita.com/irico/items/64391ef45e5d71dde147
↑上記の手順でwpのローカル環境を構築した場合を想定。2MBの制限
All-in-One WP MigrationでWPの環境をローカルに持ってこようとしたら、
最大アップロードファイルサイズ:2MB の部分で弾かれてしまいます。解決法
dockerの中にphp.iniを作る。
そこでファイルアップロード制限の設定部分を変える。
ちなみに雛形があるのでそれを使いましょう。docker exec -it {docker名} /bin/bashでdocker内に入る。
cd ../../../usr/local/etc/php/でphp.iniの雛形部分に移動。
ls
を叩くと php.ini-developmentとphp.ini-productionがあります。
https://unskilled.site/dokcer%E3%81%AE%E5%85%AC%E5%BC%8Fwordpress%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%AEphp-ini%E3%81%AE%E5%A0%B4%E6%89%80/
のサイトで違いを参照されたし。
php.ini-developmentが色々エラーを出してくれます。でもセキュリティー等を考えると本番で使用するものはphp.ini-productionがいいようです。cp php.ini-production php.iniでphp.iniファイルを作りましょう。
vi php.iniで中身を編集。
viコマンドが見つからない
https://qiita.com/YumaInaura/items/3432cc3f8a8553e05a6e
上記のサイトを参考にしました。
私はMacなので、apt-get update apt-get install vimでvi/vimコマンドをインストール。
ファイル編集
/upload_max_filesize
でupload_max_filesizeが書かれた箇所を検索して、2Mの部分を編集しましょう。
こちらはアップロードの上限容量になります。
/post_max_size
でpost_max_sizeも検索し、記述を変更しましょう。
こちらはPOSTデータの上限容量になります。編集が終わったら、
exitでdockerから抜けます。
あとはdockerを再起動すれば2MB制限が無くなります!
- 投稿日:2019-12-18T13:14:55+09:00
コンテナデバッグの底力を感じてください 〜VSCodeの品格
概要
Dockerfileを用意してコンテナ上で開発するときの話。
コンテナ内にローカルのフォルダをマウントして、ローカルファイルを編集してもいいけど、コンテナ内のファイルを直接触りたい。でもvimでいつも触ってます。。
コンテナ内のC++ファイルをVSCodeでデバッグできたら嬉しいけど、結構めんどくさかったから諦めてしまいました。。
そんなあなたに朗報!!!
マイクロソフト大先生がすごい拡張機能を出してくれました!!素敵やん!!VSCodeによる デバッグ環境の構築
ここでは、VSCodeを使って、
- コンテナ内にアクセスして、ローカルファイルと同じ感覚で編集する。
- 上の環境でC++のソースコードをデバッグ(ブレークポイントなど)する。 ことを目標とします。
1 コンテナにリモートアクセス
まず、以下のマイクロソフトの
Remote Development
という拡張機能をインストールしてください。インストールするとVSCodeの左下に緑の
Open a remote window
というボタン(下図)が出てくるので、クリックし、つなぎたいDockerコンテナを選択します。
すると、新しいウィンドウが開き、ここで編集するとコンテナ内のファイルを直接編集できます。
めっちゃ簡単やん、、すばらしい、、、、2 C++ のデバックをVSCodeで行う
F1を押して、tasksと入力すると、
configure tasks
みたいなのが出てくるので、クリックするとtasks.json
に飛びます。
そして、tasks.json
をtasks.json{ "version": "2.0.0", "tasks": [ { "label": "echo", "type": "shell", "command": "自分がいつもc++ファイルをビルドするときに打つコマンドを書いてください〜 例)cmake. && make とか", "group": { "kind": "build", "isDefault": true } } ] }上のように編集します。このとき、コマンドは.vscodeフォルダがあるところからの相対パスで書くことに注意!
tasks.json
を実行してc++のファイルをビルドしたいときは、Ctrl + Shift + B
で実行できます。さらに、F1から、
launch
とすると、launch.json
を作ることができます。そこに、launch.json{ "version": "0.2.0", "configurations": [ { "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", "program": "デバッグしたいビルド後のファイルへのパスを書きましょう〜", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } ] }上のようにlaunch.jsonを書くと、左の虫のマークから、デバッグができます。(いつものように、F5から実行。)
このとき、コンテナ内にgdb
が入っていることを確認してください。入っていないときは、apt-get install gdb
で簡単にインストールできます。
結果 コンテナ上でC++のデバッグ簡単にできるやん!!
マイクロソフト先生ありがとう....
おわり。
- 投稿日:2019-12-18T12:49:26+09:00
Docker for Windowsで "error during connect~" のエラーが出たときの対処法
Docker for WindowsをインストールしているWindows PCにて、PC起動時などに以下のダイアログが表示されることがあります。これの対処法。
誤った対処法
- とにかく「Reset to factory defaults」をクリックする
- 画面に従って処理を続ける
このボタン配置だと押したくなりますよね?私は押したくなる。「Upload crash Report」では何も解決しなそうだし、まさかQuitで何もせずに終了するはずもなく。
この「Reset to factory defaults」ボタン、要はdockerの初期化ボタンです。結果的に目先のエラーは直りますが、そもそもイメージとかビルドされたコンテナとかも全部なくなります。
今までこちらの方法で対処してました。
ただ、コンテナ復活させるのにかなりの時間がかかります。正しい対処法
- "Quit"を押してダイアログを閉じる
- WindowsのサービスからDockerサービス1を再起動する
これでだいたい直る、そうです。(ソースはこちら)
どうしても直らなかったら「Reset to factory defaults」が必要かもしれませんが、まずはサービスの再起動で直るかどうかを確認してみましょう。まとめ
ダイアログが表示されてボタンがあるとつい押したくなってしまいますが、ボタンを押すのが必ずしも正とは限りません。
エラーのダイアログが表示されても冷静に対処しましょう。
私の環境では"com.docker.service"という名前でした ↩
- 投稿日:2019-12-18T11:45:14+09:00
Docker入門 〜Docker-compose, ネットワーク, ボリューム編〜
前回の記事
Docker入門 ~Dockerfile編~
の続きです。Docker-compose
Docker-composeは、複数のコンテナを簡単に操作できる仕組みです。
使用したいコンテナの数が増えるとdockerコマンドをうつのが大変ですが、docker-compose
コマンドで楽になります。ファイル構成は以下とします。
. ├── docker-compose.yml ├── mysql │ ├── Dockerfile │ └── my.cnf └── public └── index.html
mysqlディレクトリの内容
DockerfileFROM mysql:5.7.27 RUN apt-get update \ && apt-get install -y locales \ && rm -rf /var/lib/apt/lists/* \ && echo 'ja_JP.UTF-8 UTF-8' >> /etc/locale.gen \ && locale-gen ja_JP.UTF-8 ENV LANG ja_JP.UTF-8 COPY ./my.cnf /etc/mysql/conf.d/my.cnfmy.conf[client] default-character-set=utf8mb4 [mysqld] character-set-server=utf8mb4docker-compose.yml
docker-compose.ymlで、docker-composeコマンドでまとめて起動するコンテナの設定を記述します。
docker-compose.ymlversion: '3.7' services: php: image: my-php-apache:7.3.10 ports: - 80:80 - 443:443 networks: - web volumes: - ./:/var/www mysql: build: ./dockerfiles/mysql expose: - 3306 networks: - web volumes: - mysql:/var/lib/mysql environment: - MYSQL_DATABASE=laravel - MYSQL_USER=laravel - MYSQL_PASSWORD=secret - MYSQL_ROOT_PASSWORD=secret networks: web: volumes: mysql:上記では、phpコンテナとmysqlコンテナを設定しています。
docker-compose up
コマンドで、コンテナをまとめて起動できます。$ docker-compose up Creating network "sample_web" with the default driver Creating volume "sample_mysql" with default driver Creating sample_php_1 ... done Creating sample_mysql_1 ... done Attaching to sample_php_1, sample_mysql_1docker-compose.yml解説
上記ymlファイルの解説です。
docker-compose.ymlversion: '3.7'Docker-compose.ymlの記述方法のバージョンを指定しています。古いバーションだと使用できないキーなどがあります。
docker-compose.ymlservices: php: ... mysql: ...Docker-composeはコンテナをサービスとして管理します。ここではphpとmysqlのコンテナ設定を書いていきます。
docker-compose.ymlservices: php: image: my-php-apache:7.3.10 ports: - 80:80 - 443:443 networks: - web volumes: - ./:/var/www
- image - 使用するイメージ
- ports - ポートのバインディング。
ホスト:コンテナ
の順番でかく- networks - コンテナが所属するネットワーク(後述)
- volumes - マウントするボリューム(後述)
ボリュームは前回利用しましたが、データをコンテナとは別に管理して永続化する仕組みでした。後ほどネットワークと合わせて詳しく解説します。
docker-compose.ymlmysql: build: ./mysql expose: - 3306 networks: - web volumes: - mysql:/var/lib/mysql environment: - MYSQL_DATABASE=laravel - MYSQL_USER=laravel - MYSQL_PASSWORD=secret - MYSQL_ROOT_PASSWORD=secret
- build - Dockerfileのパス
イメージではなくDockerfileも指定できます。
- expose - 他のサービスに公開するポート(ホストからはアクセスできない)
- environment - コンテナ内で使用できる環境変数
特定の環境変数を設定しておくと楽にカスタマイズできるように、ベースイメージ側で準備してくれていることがあります。
MySQLイメージのDockerHubページを見ると、MYSQL_DATABASEでデータベース名を設定できると分かります。
ここでは上からデータベース名、データベースのユーザー名、ユーザーのパスワード、ルートユーザーのパスワードを設定しています。Laravelからデータベースに接続するときに、この情報で接続します。docker-compose.ymlnetworks: web: volumes: mysql:各サービスで使用するネットワーク・ボリュームを明示します。忘れると動作しません。
Dockerネットワーク
Docker-composeというよりDockerの仕組みですが、ここで説明します。
コンテナは同じ仮想ネットワークに配置されないと、相互にやりとりできません。なので、ApacheのコンテナとMySQLのコンテナは同じネットワークにしてあげます。
docker-compose.ymlservices: php: networks: - web mysql: networks: - web networks: web:同じネットワークにすると、コンテナ内から他のコンテナにアクセスするときに、サービス名でアクセスできるようになります。
phpコンテナに配置したLaravelアプリケーションから、MySQLコンテナにアクセスするには.envファイルをこう書きます。.envDB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=laravel DB_PASSWORD=secretDB_HOSTが
mysql
とサービス名になっていて、これで繋がります。内部的にはDockerがDNSサーバーを用意して、名前解決してくれるようです。Dockerボリューム
こちらもDocker-composeというよりDockerの仕組みですが、ここで説明します。
MySQLコンテナを立ち上げて、DBにデータを保存してもコンテナを削除するとそのデータは消えてしまいます。データを永続保存するための仕組みがボリュームです。
ボリュームはコンテナとは切り離して管理されるもの、ということです。ボリューム一覧は以下のコマンドで確認できます。
$ docker volume ls DRIVER VOLUME NAME local tmp ...ボリュームには以下の3種類があります。
- ホスト(host)
- 匿名(anonymous)
- 名前付き(named)
ホストボリューム
-v /host/path:/container/path
でホストのパスをコンテナのパスにマウントし、ボリュームとします。$ docker container run -dit -v $HOME/tmp:/tmp alpine上記の例ではコンテナを削除しても、/tmpの内容は$HOME/tmpに残ります。そしてホストボリュームは
docker volume ls
には表示されません。匿名ボリューム
-v /container/path
で、匿名ボリュームです。$ docker container run -dit -v /tmp alpineDockerが隠蔽して管理するボリュームで、ハッシュ値がボリューム名となります。
$ docker volume ls DRIVER VOLUME NAME local a1138c254e5df7d419191d29e9e7e5acaf6389d69521c09eb00abe05889151ad名前付きボリュームがなかった時代に使われていたようで、現在は名前付きボリュームを使います。
docker container run --rm
で立ち上げたコンテナが削除される時、匿名ボリュームも削除されるという特徴があります。名前付きボリューム
-v name:/container/path
で名前付きボリュームです。$ docker container run -dit -v tmp:/tmp alpineこちらもDockerが隠蔽して管理するボリュームですが、名前がありアクセスしやすいです。
$ docker volume ls DRIVER VOLUME NAME local tmpまた
docker container run --rm
で立ち上げたコンテナが削除されても名前付きボリュームは削除されません。どの種類のボリュームにするか
最初のdocker-compose.ymlを見ると、phpコンテナはホストでファイルを編集したいので、ホストボリューム
./:/var/www
にしています。
MySQLコンテナは、特にホストでMySQLが管理するファイルをいじることはないですから、名前付きボリュームmysql:/var/lib/mysql
です。ただホストボリューム./.db:/var/lib/mysql
などにしても問題はないと思います。また、前回でやったcomposerの例で考えてみましょう。
composer install
するためのcomposer.jsonや、インストール結果のvendorディレクトリなどをコンテナとやりとりするだけであれば、ホストボリュームでいいです。
今後別のコンテナでcomposer install
するためのキャッシュは、名前付きボリュームでどこからでも参照できるようにしておきましょう。$ docker container run --rm -it -v $PWD:/app -v composer_cache:/tmp composer install上記なら、2回目以降は以下のようにキャッシュからインストールしてくれます。
$ docker container run --rm -it -v $PWD:/app -v composer_cache:/tmp composer install Loading composer repositories with package information Installing dependencies (including require-dev) from lock file Package operations: 84 installs, 0 updates, 0 removals - Installing doctrine/inflector (v1.3.0): Loading from cache - Installing doctrine/lexer (1.1.0): Loading from cache ...ボリュームにファイルがあると
ボリュームにファイルあり、コンテナになし
ボリュームのファイルがコンテナにコピーされるボリュームにファイルなし、コンテナにあり
コンテナのファイルがボリュームにコピーされる両方にファイルあり
コンテナのファイルがなくなり、ボリュームのファイルがコンテナにコピーされる実際にdocker-composeコマンドを使ってみよう
docker-compose.ymlがあれば、以下のコマンドでコンテナを一気に立ち上げることができます。
$ docker-compose up起動したコンテナ、ネットワーク、ボリュームを確認してみましょう。
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af5e814670de my-php-apache:7.3.10 "docker-php-entrypoi…" 5 minutes ago Up 5 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp sample_php_1 e4116e1a3bfa sample_mysql "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 3306/tcp, 33060/tcp sample_mysql_1 $ docker network ls NETWORK ID NAME DRIVER SCOPE 81e33015a6f9 bridge bridge local e2eab5ac1197 host host local a8432cc388c6 none null local 37b562bfd9c1 sample_web bridge local $ docker volume ls DRIVER VOLUME NAME local sample_mysqlネットワークのbridge,host,noneは、デフォルトで用意されているネットワークなので気にしないでください。
dockerコマンドと同じように、
exec <service> <command>
でコンテナ内でコマンドを実行できます。$ docker-compose exec php bash root@026c8f03e602:/var/www#MySQLに接続するのであれば
$ docker-compose exec mysql mysql -u laravel -D laravel -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g.コンテナ削除も
docker-compose down
でまとめてできます。コンテナとネットワークが削除され、ボリュームは残ります。$ docker-compose down Stopping sample_php_1 ... done Stopping sample_mysql_1 ... done Removing sample_php_1 ... done Removing sample_mysql_1 ... done Removing network sample_webプロジェクト
コンテナ、ネットワーク、ボリューム名が
sample_*
になっています(コンテナ名はls結果の一番右に書いてあります)。これはsampleディレクトリ下でdocker-compose up
したからです。他のディレクトリで
docker-compose up
すると、そのディレクトリ名がプリフィックスになります。ディレクトリ名だとわかりにくい場合は、環境変数COMPOSE_PROJECT_NAMEや-p
オプションでプリフィックスを指定できます。
docker-composeコマンドは.envファイルをみてくれるので、以下のようにしましょう。.envCOMPOSE_PROJECT_NAME=プロジェクト名プロジェクト固有のイメージ
docker image ls
コマンドで所持イメージを確認してみます。$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE sample_mysql latest c8914e3551fe 35 seconds ago 385MB my-php-apache 7.3.10 ed7f24566ef1 About a minute ago 452MB php 7.3.10-apache b83ebda0d7d4 7 weeks ago 410MB mysql 5.7.27 383867b75fd2 3 months ago 373MBphpとmysqlはベースにした公式イメージで、my-php-apacheは前回自分でビルドしたイメージでした。
sample_mysqlは、docker-compose up
した時にビルドされたイメージです。docker-compose.ymlにbuildを指定すると、プロジェクトごとにイメージがビルドされます。今回は
docker-compose.ymlmysql: build: ./mysqlとしていたので、sampleがプリフィックスのプロジェクト固有のmysqlイメージになりました。
プロジェクトごとにイメージを持ちたいならbuildを、使いまわしたいなら最初に
docker build
しておき、それをimageに指定すれば良いでしょう。終わりに
Docker-composeを使うことができれば、開発環境は構築できると思います。
他のイメージを使えば、PostgreSQLやRedisサーバー、メール送信のテストを行えるMailHogなどを立ち上げてLaravelで使用できるので試してみてください。
- 投稿日:2019-12-18T11:25:22+09:00
docker-composeでexit status 1
はじめに
macOS Mojave 10.14.6
Docker 2.1.0.5
とりあえず
$ docker-compose up ... front_nuxt | npm ERR! Exit status 1 front_nuxt | npm ERR! front_nuxt | npm ERR! Failed at the Musclers@1.0.0 dev script. front_nuxt | npm ERR! This is probably not a problem with npm. There is likely additional logging output above. front_nuxt | front_nuxt | npm ERR! A complete log of this run can be found in: front_nuxt | npm ERR! /root/.npm/_logs/2019-12-18T01_41_30_431Z-debug.log front_nuxt | front_nuxt exited with code 1といってフロントくん(nuxt)が起動しない
$ docker-compose ps Name Command State Ports ---------------------------------------------------------------------------- api_rails bash -c rm -f 'tmp/pids/se ... Up 0.0.0.0:8080->8080/tcp db_psql docker-entrypoint.sh postgres Up 5432/tcp front_nuxt docker-entrypoint.sh npm r ... Exit 1 0.0.0.0:3000->3000/tcpまぁ、だよね
原因
これがイマイチわからない。
やったこと
prune
でimageを一括削除した。$ docker-compose down $ docker system prune --volumes # docker system pruneではvolumeまで削除してくれない $ docker-compose up --build # build忘れないようにねで、buildが終わった後、無事起動しました。
最後に
最後にって書く必要あるのかわからないけどrailsとか使ってるなら、
db:create
、migrate
、db:seed
忘れないようにね。
DB空っぽだから何もできずに発狂した人もいるらしい←
- 投稿日:2019-12-18T02:32:53+09:00
LaTeXで年賀状を作る
はじめに
急に年賀状を用意しないといけない!という時どういったツールをつかうとよいだろうか?PowerPointなどのスライド作成ソフトを作ったり、あるいは専用のツールを購入するという手もあるかもしれない。この記事では、フリーソフトウェアである$\mathrm{\LaTeX}$を利用して美しい年賀状をつくる方法を紹介する。この方法は$\mathrm{\LaTeX}$とjletteraddressクラス、さらにそれをコンパイルする環境をDockerで作成したことによって、特に$\mathrm{\LaTeX}$の知識がなくとも勘で年賀状を出力できるのが利点である。また著者の知るかぎり年賀状を作るソフトウェアは数式やソースコードの出力に対応しているとは言えないだろうが、$\mathrm{\LaTeX}$では既存の$\mathrm{\LaTeX}$資産を利用できるため年賀状に数式やソースコードを容易に埋め込むことができるうえ、個人の論文や同人誌など他の$\mathrm{\LaTeX}$文書からデータを流用できるという利点もある。
上記のGitHubリポジトリにコードの一覧がある。この記事について疑問や改善点を見つけた場合は、気軽にコメントなどで教えてほしい。
成物果
このような年賀状を出力できる。
あとはこれを編集して印刷するだけ!
使い方
次のような手順で、すごく簡単に
のような年賀状を得ることができる。なおDockerと
docker-compose
が必要である。
git clone git@github.com:y-yu/new-year-letter.git
cd new-year-letter
docker-compose up
いったんこれで
letter.pdf
を得ることができる。あとは好みにあわせてletter.tex
を書き換えていけばよい。本文の編集
$\mathrm{\LaTeX}$ファイルの編集というとキツい印象があるかもしれないが、実はサンプルは非常にシンプルに書かれている。
letter.tex\documentclass{jletteraddress} \usepackage{amsmath} \usepackage[papersize={100mm, 148mm}, margin=0mm]{geometry} \newcommand{\bra}[1]{\mathinner{\left\langle{#1}\right|}} \newcommand{\ket}[1]{\mathinner{\left|{#1}\right\rangle}} \newcommand{\braket}[2]{\mathinner{\left\langle{#1}\middle|#2\right\rangle}} \sendername{吉村 優} \senderaddressa{茨城県つくば市天王台1-1-1} \senderaddressb{筑波大学第三エリア3C212} \senderpostcode{3058573} \renewcommand{\baselinestretch}{1.2} \begin{document} \pagestyle{empty} \addaddress {山田 太郎}{様} {1138654} {東京都文京区本郷7-3-1} {} \newpage \newgeometry{ top=10mm, left=10mm, right=10mm, bottom=5mm } \begin{abstract} \footnotesize この文章では、新年の挨拶を述べるための手紙である``年賀状''を作る方法について述べる。 従来の年賀状を作成するソフトウェアは数式やソースコードの埋め込みが貧弱であったが、 我々はそれを解決す方法として組版ソフト\LaTeX を利用する方法を示す。 In this paper, we describe how to make a letter to hello new year. For conventional softwares that makes those letter, it's difficult to write mathmatical expressions or programming source code. We show how we solve that problem with \LaTeX. \end{abstract} \section*{Introduction} 年賀状は年の始めに互いに送信する手紙のことである。 近年はLINEなどに対抗するため、年賀状に次のような複雑な数式を埋め込みたい ニーズが存在する。 {\scriptsize \begin{align*} \left|\braket{+}{\varphi_{0 \oplus b, 0 \oplus b}}\right|^2 &= \left\{ \begin{array}{l} \left|\braket{+}{\alpha\ket{0} + \beta\ket{1}}\right|^2 = \left|\frac{1}{\sqrt{2}}(\alpha + \beta)\right|^2 \\ \left|\braket{+}{\beta\ket{0} + \alpha\ket{1}}\right|^2 = \left|\frac{1}{\sqrt{2}}(\beta + \alpha)\right|^2 \end{array} \right\} \\ &= \frac{(\alpha + \beta)^2}{2} \end{align*} } \noindent この文章ではこのような複雑な数式を埋め込むために\LaTeX を 利用した解決方法について述べる。 \begin{flushright} \tiny This letter was generated by \LaTeX. \end{flushright} \end{document}下記にざっくりどういった意味なのか解説していく。
\sender○○○
系のコマンドが差出人の情報を示す\baselinestretch
は行間をデフォルトの1.2倍へ広げている(これは好み)\addaddress
は宛先情報\newgeometry
で余白の設定という感じで、あとは適当に
abstract
とかを消していじってみてdocker-compose up
してコンパイルしていけばOKである。これはこの記事の著者というよりもjletteraddressがすごいので、このように簡単になっている。まとめ
このようにjletteraddressを使えば$\mathrm{\LaTeX}$で簡単に年賀状を作ることができる。ただ$\mathrm{\LaTeX}$のコンパイルは慣れていないと大変であるため、著者の貢献としてそこをDockerで隠蔽した。普段、論文や同人誌の執筆などで$\mathrm{\LaTeX}$を使う人がいれば、それと同じような感覚で使えるのは利点だと思う。
参考
- 投稿日:2019-12-18T02:03:02+09:00
Docker Desktop for Windows で Windows GUI コンテナを動かす #2
これは何?
Docker Desktop for Windows で Windows GUI コンテナを動かす の続きです。
結論
次の組み合わせ
Dockerfile
使った Dockerfile です.
32bit アプリを動かすつもりなら, コメントアウトしているENV WINEARCH=win32
を有効にし, win32 環境を構築した方が良いDockerfileFROM ubuntu:18.04 # @see https://qiita.com/fkshom/items/53de3a9b9278cd524099 RUN sed -i.bak -e "s%http://[^ ]\+%http://ftp.jaist.ac.jp/pub/Linux/ubuntu/%g" /etc/apt/sources.list RUN set -eux; \ dpkg --add-architecture i386 \ && apt-get update \ && apt-get install -y --no-install-recommends \ software-properties-common \ apt-transport-https \ gpg-agent \ curl \ && curl -L -O https://dl.winehq.org/wine-builds/winehq.key \ && apt-key add winehq.key \ && apt-add-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ bionic main' \ && rm winehq.key \ && apt-get update \ && apt-get install -y --install-recommends \ winehq-stable \ && apt-get install -y --no-install-recommends \ winetricks \ && apt-get remove --purge -y \ software-properties-common \ && apt-get autoremove -y \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* COPY local.conf /etc/fonts/local.conf # for 32bit environment only #ENV WINEARCH=win32 RUN set -eux; \ apt-get update \ && apt-get install -y --no-install-recommends \ xvfb \ && mkdir -p /root/.cache/wine \ && cd /root/.cache/wine \ && curl -L -O http://dl.winehq.org/wine/wine-gecko/2.47/wine_gecko-2.47-x86_64.msi \ && curl -L -O http://dl.winehq.org/wine/wine-gecko/2.47/wine_gecko-2.47-x86.msi \ && curl -L -O http://dl.winehq.org/wine/wine-mono/4.7.5/wine-mono-4.7.5.msi \ && winetricks nocrashdialog win10 \ && xvfb-run wineboot -u \ && apt-get remove --purge -y \ xvfb \ && apt-get autoremove -y \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /root/.cache/wine/wine*.msilocal.conf は、 Connect to the container and create a '/etc/fonts/local.conf' file そのままです。 VcXsrv でも使えると思います。
local.conf<?xml version="1.0"?> <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> <fontconfig> <dir>/mnt/winfonts</dir> </fontconfig>wineboot は DISPLAY 環境変数が未設定だと途中で abort します. なので、 xvfb を使います.
また, 単に xvfb-run に GUI を捨てると wine-mono と wine_gecko の download を促す dialog が表示されてしまいます.
この問題を回避するため, あらかじめ wine-mono と wine_gecko の .msi を.cache/wine
に配置しています. ここに .msi ファイルがあると, wineboot がキャッシュから mono と gecko を install してくれます.現状の Dockerfile だと, winehq-stable のバージョンが変わったら, wget の download 先を書き換える必要があり, 面倒...
コンテナの起動
docker image を
wine:latest
で作成したとします.X410 の場合
launch.cmdsetlocal cd %~dp0 docker run -it --rm -v C:/Windows/Fonts:/mnt/winfonts:ro -v "%CD%:/root/workspace" -w /root/workspace -e DISPLAY=docker.for.win.localhost:0.0 wine %*VcXsrv の場合
試していませんが、多分これでOKと思います
下記のバッチファイルから起動すると, VcXsrv のxhost +
と docker run の DISPLAY を設定しに行きます.launch.cmdsetlocal cd %~dp0 set ARGS=%* set DISPLAY=127.0.0.1:0.0 "%PROGRAMFILES%\VcXsrv\xhost" + CHCP 437 for /f "tokens=3 usebackq" %%i in (`netsh interface ipv4 show address "vEthernet (Default Switch)"^|find "IP Address:"`) do @set "IP=%%i" docker run -it --rm -v C:/Windows/Fonts:/mnt/winfonts:ro -v "%CD%:/root/workspace" -e DISPLAY=%IP%:0.0 wine %ARGS%Dockerfile で ENTRYPOINT を wine にしていないので bash が走るのがイマイチなので適当に直してください。
参考にしたところ
apt-getの利用リポジトリを日本サーバーに変更する
Installing WineHQ packages
X410
Launching Linux GUI apps from the Docker Console in Token2Shell (Store App)
How to change the codepage for DOS batch files to ANSI