- 投稿日:2019-10-23T23:05:41+09:00
dockerでnginxを起動しようと思ったら、80番ポートがすでに使われていて起動できなかった
- まずは80ポートを何が掴んでいるのか確かめる
$ sudo lsof -i :80どうやら80番ポートがnginxに大量に掴まれている様子
- killしてみる
$ kill (PID) # ここでいうと Kill 3040 とかこれで狙って起動している物を消せる
が、
俺のはなぜか無限に出てくる...
- 効率よく消すにはこれがいい
$ kill $(lsof -t -i:80)これで$sudo lsof -i :80で出てきた一覧にある15個ほどのポートは消せる。
ただ、僕の場合は消してもまた同じ量80番ポートが掴まれていた
何度消しても何度も出てくる...色々調べてみた結果
これ↓でnginx全てを落とせるらしい
$ sudo nginx -s stopようやく全て消えたので、dockerでnginxを立ち上げてみると起動できた。
一度dockerを落としてもう一度起動してみても問題なく起動できた!
理由がなんだかわからないが、ひとまず動いたので良しとします!笑
- 投稿日:2019-10-23T22:53:16+09:00
【メモ】Rails APIモード × MySQL5.7 × Docker で環境構築
はじめに
久しぶりにDockerを作成したら所々躓いたので要点をメモ
手順
- ディレクトリ用意&移動
Gemfile,Gemfile.lock,Dockerfile,docker-compose.ymlを作成- 2.のファイルにコード記述
$ docker-compose build$ docker-compose run app rails new --api . --force --no-deps --database=mysqlconfig/database.ymlを修正$ docker-compose build --no-cache$ docker-compose up$ docker-compose run app rails db:create手順3, 6で用意するファイルについて
Gemfilesource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } source "https://rubygems.org" gem 'rails', '6.0.0'DockerfileFROM ruby:2.6.5 ENV LANG C.UTF-8 # install required libraries RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs RUN gem install bundler -v 2.0.2 # install bundler RUN gem install bundler WORKDIR /tmp ADD Gemfile Gemfile ADD Gemfile.lock Gemfile.lock RUN bundle install WORKDIR /app COPY . /appdocker-compose.ymlversion: '3' services: mysql: image: mysql:5.7 command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql environment: MYSQL_DATABASE: app_development MYSQL_USER: root MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password app: tty: true stdin_open: true build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/app ports: - "3000:3000" depends_on: - mysql volumes: mysql-data: driver: localconfig/database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password host: mysql development: <<: *default database: app_development test: <<: *default database: app_test # 一例です。productionについてはデプロイする際に注入する環境変数を適宜用意して下さい。 production: <<: *default username: <%= ENV['MYSQL_USER'] %> password: <%= ENV['MYSQL_ROOT_PASSWORD'] %> database: <%= ENV['MYSQL_DATABASE'] %> host: <%= ENV['MYSQL_HOST'] %> socket: <%= ENV['MYSQL_SOCKET'] %>
- 投稿日:2019-10-23T22:51:22+09:00
docker超入門
コンピュータに詳しくない自分が急にDockerを使う必要が出てきたときのノートです.
同じような状況に陥った人の参考になれば幸いです.超入門
dockerおよびnvidia-dockerはinstall済みの場合を想定します.
難しいことを考えずにただ使うでけだと, 以下の3つのステップで大丈夫です.
- Docker Imageを用意する.
- Docker Imageを使って, Docker Containerを起動する.
- 起動したContainer内に入って作業する.
Docker Imageを用意する.
Docker Imageを用意する方法は, 自分が知っている限り以下の2つあります.
- DockerfileでImageをbuildする.
- 既存のDocker Imageをpullしてくる.
Dockerfileが既に用意されている場合, 以下のコマンドでImageをbuildできます.
$ docker image build -f ./Dockerfile -t <repository name:tag name> .Dockerfileがない場合は, Dockerhubで自分の作業に必要なDocker Imageをpullできます.
DockerhubにあるImageは公式のものほど動作が保証されているので安心して使えます.
例えば, nvidia/cudaのGPU環境が必要な場合は,$ docker pull nvidia/cudaのコマンドだけでImageをpullできます.
逆に自分がbuildしたImageをdockerhubにpushしておけば, 違うマシンでImageをbuildし直す必要がないので非常に便利です.用意したDocker Imageは,
$ docker image lsで確認できます.
Containerの起動
作成したDocker Imageを使って, Docker Containerを起動します.
$ docker container run -it -p <host:cont> -v <host dir:cont dir> --name <container name> -d <image name>GPU環境のcontainerを起動する場合は,
dockerをnvidia-dockerに変えてください.
-pはポートフォワード,-vはdirectoryのmountのオプションなのでよしなに設定してください.起動したcontainerは,
$ docker ps -aで確認できます.
-aを入れると, stopしているcontainerも確認できます.docker container内に入る
$ docker exec -it <container id or name> bashこれだけです. ここまでで, dockerよくわかってないけど作業できる状態までなります!
使用例
自分はjupyterで作業したかったので, containerを起動する時に
-p 8000:8888と設定して,
container内で以下のコマンドでjupyterを立ち上げます.$ jupyter notebook --ip=0.0.0.0 --allow-rootもしくはjupyterのconfigを設定するのが良いかもしれないです.
最後に
docker, 使うだけなら簡単ですね!!
当然dockerはもっと便利なツールなので, もう少し勉強します.Dockerfileの書き方とか,docker-composeの使い方辺りかな.Qiita初投稿なので, 内容だけでなくマナー的なところでご指摘あればよろしくお願いします.
- 投稿日:2019-10-23T22:46:34+09:00
Dockerfile作成からDocker-composeまでの流れ
前提:Dockerがインストールされている環境
Docker Composeのインストール
Dockerがインストールされている環境で以下を実行
$ curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-composeDockerfile を作成
docker buildする為の手順を書いたファイルFROM python:3.6 RUN mkdir /code VOLUME /code ADD main.py /code/ ADD requirements.txt /code/ WORKDIR /code RUN apt-get update RUN pip install --upgrade "pip<10" \ && pip install flask \ && pip install -r requirements.txt CMD ["python", "main.py"]Docker-compose.yml を作成
複数のコンテナを組み合わせて1つのアプリケーションとして構成を定義するファイルdocker-compose.ymlversion: '2' services: flask: build: ports: - "5000:5000" volumes: - ".:/code"実行
$ docker-compose up -dで、Dockerfileから独自のイメージをビルドし、
コンテナを起動してくれる。参考
Python+Flask環境をDockerで構築する
Docker | docker build と Dockerfile でイメージをビルドする基本
Dockerfileを書いてみる
Docker Compose - docker-compose.yml リファレンス
Docker入門(第六回)〜Docker Compose〜
- 投稿日:2019-10-23T21:01:51+09:00
Ansible Playbook検証環境構築2 (2019版)
目的
Ansible Playbook検証環境構築 (2019版)では、ローカルに色々導入したので、ローカルにあまり多くを導入しない様に内容を更新した。
ansible controllerもdockerコンテナとし、検証環境もdockerとしてKitchenCIを回す環境
MAC
macOS 10.14.6ローカルに以下を導入
- docker desktop (2.1.0.3)
- Chef Workstation (0.3.2) https://downloads.chef.io/chef-workstation/
環境変数設定
$ echo 'eval "$(chef shell-init bash)"' >> ~/.bash_profile $ . ~/.bash_profileローカルに導入するgem
- kitchen-ansible (0.50.0)
- kitchen-docker (2.9.0)
$ gem install kitchen-ansible $ gem install kitchen-docker環境構築
ansible controllerもkitchenCIで導入する
(なお、DockerFileでも可能と思える)
その為、以降はcdやviなどの基本的なコマンド以外では、kitchenコマンドのみで完結。$ mkdir ansible_controller $ cd ansible_controller $ vi kitchen.yml ... $ vi site.yml ...kitchen.yml--- driver: name: docker run_options: >- -v /var/run/docker.sock:/var/run/docker.sock -v /usr/local/bin/docker:/bin/docker provisioner: name: ansible_playbook chef_bootstrap_url: nil hosts: ansible-controller playbook: site.yml platforms: - name: centos-7 suites: - name: ansible-controller
- /var/run/docker.sockを共有することで、dockerコンテナからdockerの操作を可能とする。
- この場合、コンテナで制御を奪われるとベースOSも制御を奪われるので要注意
- kitchen-ansible は対象にansibleを導入し、ローカルモードで実行する。
- この導入されたansibleをそのまま利用する。
-v を追加し、ローカルのansible repoをansible controllerコンテナと共有させることも可能
centos-7を対象としている。ubuntu-16.04 とした場合、幾つか修正が必要となる可能性がある。
site.yml--- - hosts: all gather_facts: false tasks: - name: install the chef-workstation rpm from a remote repo yum: name: https://packages.chef.io/files/stable/chef-workstation/0.9.42/el/7/chef-workstation-0.9.42-1.el7.x86_64.rpm - name: add 'eval "$(chef shell-init bash)"' to ~/.bash_profile lineinfile: dest: ~kitchen/.bash_profile line: eval "$(chef shell-init bash)" become: true become_user: kitchen - name: gem install shell: | set -e eval "$(chef shell-init bash)" gem install kitchen-ansiblepush gem install kitchen-docker become: true become_user: kitchenansible controllerのdockerコンテナ起動、作成
$ kitchen test -d never -----> Starting Kitchen (v1.25.0) -----> Cleaning up any prior instances of <ansible-controller-centos-7> ... PLAY [all] ********************************************************************* TASK [install the chef-workstation rpm from a remote repo] ********************* ok: [localhost] TASK [add 'eval "$(chef shell-init bash)"' to ~/.bash_profile] ***************** changed: [localhost] TASK [gem install] ************************************************************* changed: [localhost] PLAY RECAP ********************************************************************* localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Downloading files from <ansible-controller-centos-7> Finished converging <ansible-controller-centos-7> (5m22.82s). -----> Setting up <ansible-controller-centos-7>... Finished setting up <ansible-controller-centos-7> (0m0.00s). -----> Verifying <ansible-controller-centos-7>... Preparing files for transfer Transferring files to <ansible-controller-centos-7> Finished verifying <ansible-controller-centos-7> (0m0.00s). Finished testing <ansible-controller-centos-7> (5m28.24s). -----> Kitchen is finished. (5m29.68s)これでansible controllerコンテナが起動する。
削除は、kitchen destroyで可能。
kitchenコマンドからdocker stopやstartなど細かい操作は出来ないので、必要があればdockerコマンドを使用。ansible controllerにログインして利用
$ kitchen login Last login: Wed Oct 23 07:44:58 2019 from 172.17.0.1 [kitchen@7b012ce1d2a9 ~]$ id uid=1000(kitchen) gid=1000(kitchen) groups=1000(kitchen) [kitchen@7b012ce1d2a9 ~]$ pwd /home/kitchen [kitchen@7b012ce1d2a9 ~]$ ansible --version ansible 2.8.5 config file = /etc/ansible/ansible.cfg configured module search path = [u'/home/kitchen/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /usr/bin/ansible python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] [kitchen@7b012ce1d2a9 ~]$ kitchen --version Test Kitchen version 2.3.3 [kitchen@7b012ce1d2a9 ~]$ gem list | grep kitchen kitchen-ansiblepush (0.10.1) kitchen-azurerm (0.14.9) kitchen-digitalocean (0.10.4) kitchen-docker (2.9.0) kitchen-dokken (2.7.0) kitchen-ec2 (3.2.0) kitchen-google (2.0.1) kitchen-hyperv (0.5.3) kitchen-inspec (1.2.0) kitchen-vagrant (1.6.0) kitchen-vcenter (2.5.2) test-kitchen (2.3.3) [kitchen@7b012ce1d2a9 ~]$ mkdir roles [kitchen@7b012ce1d2a9 ~]$ cd roles/ [kitchen@7b012ce1d2a9 roles]$ ansible-galaxy init role01 - role01 was created successfully [kitchen@7b012ce1d2a9 roles]$ cd role01/ [kitchen@7b012ce1d2a9 role01]$ vi kitchen.yml ... [kitchen@7b012ce1d2a9 role01]$ vi site.yml ... [kitchen@7b012ce1d2a9 role01]$ vi tasks/main.yml ... # 以下はInSpecの設定 [kitchen@7b012ce1d2a9 role01]$ mkdir -p test/integration/default [kitchen@7b012ce1d2a9 role01]$ vi test/integration/default/default_test.rb ...KitchenCI設定
kitchen.yml--- driver: name: docker use_sudo: true use_internal_docker_network: true provisioner: name: ansible_push chef_bootstrap_url: nil platforms: - name: centos-7 suites: - name: ansiblepush provisioner: playbook: ./site.yml verifier: name: inspec inspec_tests: - test/integration/defaultkitchen-dockerとkitchen-ansiblepushを使用。
kitchen-ansiblepushは、ターゲットにansibleを導入せずにcontrollerのansibleを使用する。プレイブック (site.yml)
site.yml--- - hosts: all #gather_facts: false become: true tasks: - name: include_role include_role: name: "../{{ lookup('env', 'PWD') | basename }}"ここではテスト実行時のカレントディレクトリーをロール名としてincludeしている。
ロールのtasks (tasks/main.yml)
tasks/main.yml--- - debug: msg: hello world!InSpecテスト
test/integration/default/default_test.rb# # encoding: utf-8 # This is an example test, replace it with your own test. describe port(80) do it { should_not be_listening } endテスト実施 (kitchen test -d never)
[kitchen@7b012ce1d2a9 role01]$ kitchen test -d never -----> Starting Kitchen (v2.3.3) -----> Cleaning up any prior instances of <ansiblepush-centos-7> -----> Destroying <ansiblepush-centos-7>... Finished destroying <ansiblepush-centos-7> (0m0.00s). -----> Testing <ansiblepush-centos-7> -----> Creating <ansiblepush-centos-7>... ... PLAY [all] ********************************************************************************************************************* TASK [Gathering Facts] ********************************************************************************************************* ok: [centos-7] TASK [include_role] ************************************************************************************************************ TASK [../role01 : debug] ******************************************************************************************************* ok: [centos-7] => { "msg": "hello world!" } PLAY RECAP ********************************************************************************************************************* centos-7 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 *************** AnsiblePush end run ******************* Downloading files from <ansiblepush-centos-7> Finished converging <ansiblepush-centos-7> (0m6.98s). -----> Setting up <ansiblepush-centos-7>... Finished setting up <ansiblepush-centos-7> (0m0.00s). -----> Verifying <ansiblepush-centos-7>... Loaded tests from {:path=>".home.kitchen.roles.role01.test.integration.default"} Profile: tests from {:path=>"/home/kitchen/roles/role01/test/integration/default"} (tests from {:path=>".home.kitchen.roles.role01.test.integration.default"}) Version: (not specified) Target: ssh://kitchen@172.17.0.3:22 Port 80 ✔ should not be listening Test Summary: 1 successful, 0 failures, 0 skipped Finished verifying <ansiblepush-centos-7> (0m1.13s). Finished testing <ansiblepush-centos-7> (0m9.58s). -----> Kitchen is finished. (0m13.83s)ターゲットとなる別のdockerコンテナを立ち上げ、playbook適用、およびInSpecテスト実施
kitchen list, login, destroy
[kitchen@7b012ce1d2a9 role01]$ kitchen list Instance Driver Provisioner Verifier Transport Last Action Last Error ansiblepush-centos-7 Docker AnsiblePush Inspec Ssh Verified <None> [kitchen@7b012ce1d2a9 role01]$ kitchen login Last login: Wed Oct 23 08:23:19 2019 from 172.17.0.2 [kitchen@b72f869eae28 ~]$ id uid=1000(kitchen) gid=1000(kitchen) groups=1000(kitchen) [kitchen@b72f869eae28 ~]$ ls [kitchen@b72f869eae28 ~]$ logout Connection to 172.17.0.3 closed. [kitchen@7b012ce1d2a9 role01]$ kitchen destroy -----> Starting Kitchen (v2.3.3) -----> Destroying <ansiblepush-centos-7>... PID USER TIME COMMAND 72332 root 0:00 /usr/sbin/sshd -D -o UseDNS=no -o UsePAM=no -o PasswordAuthentication=yes -o UsePrivilegeSeparation=no -o PidFile=/tmp/sshd.pid b72f869eae282ebcdff9c1a20a03b85e94bd1aa709e8e750202f5265ef7c81d4 b72f869eae282ebcdff9c1a20a03b85e94bd1aa709e8e750202f5265ef7c81d4 Finished destroying <ansiblepush-centos-7> (0m0.84s). -----> Kitchen is finished. (0m5.17s) [kitchen@7b012ce1d2a9 role01]$ kitchen list Instance Driver Provisioner Verifier Transport Last Action Last Error ansiblepush-centos-7 Docker AnsiblePush Inspec Ssh <Not Created> <None>
- 投稿日:2019-10-23T17:56:26+09:00
LaradockでLaravel環境を構築する流れとMySQL接続について
LaradockでMySQLに接続したい!!
Laradockでlaravelの開発環境を構築する方法については、公式ドキュメントや多くのQiitaの記事で説明されており、基本的にはそれに従って行けば開発環境を立ち上げることができると思います。しかし、自分が公式ドキュメントや記事通りに作業していく中でハマった点が2つあり、その解決法を探すのに時間がかかったので、ハマった点とその対処法について記録を残しておくものです
ハマった点
1 MySQLのバージョンについて
MySQLの認証方法がLaravelにサポートされてないのでエラーが出る。
MySQL 8.0.4からデフォルトの認証方式が変わり、セキュリティが強化されました。しかし、Laravel側でサポートされていないためphp artisan migrateを打っても「The server requested authentication method unknown to the client」というエラーが出ます2 .envの編集について
Laradock,Laravelの.envの編集すれば良いか、MySQLのユーザー登録をどのようにすれば良いかがわからない
1 Laradockのインストール、env編集
今回はこのようなディレクトリ構造で作業を行なっていきます
- (root)
- sampleapp
- Laradock(Laradock側)
- Laravel
- wikiLearns(Laravel側)
まずは公式ドキュメント通り
$ git clone https://github.com/laradock/laradock.git $ cd laradock $ cp env-example .envここで.envファイルを編集します
laradock.env### MYSQL ################################################ MYSQL_VERSION=5.7 //latest MYSQL_DATABASE=default MYSQL_USER=default MYSQL_PASSWORD=secret MYSQL_PORT=3306 MYSQL_ROOT_PASSWORD=root MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-initdb.dMySQLのバージョンをlatestから5.7にしました
なのでハマった点1の答えは「認証方法変更前のMySQL5.7を使おう」です。現在インストールしているMySQLも8.0.4 -> 5.7に変更しましたそれともう一つ
laradock.env### NGINX ################################################ NGINX_HOST_HTTP_PORT=8888 // 80 NGINX_HOST_HTTPS_PORT=443 NGINX_HOST_LOG_PATH=./logs/nginx/ NGINX_SITES_PATH=./nginx/sites/ NGINX_PHP_UPSTREAM_CONTAINER=php-fpm NGINX_PHP_UPSTREAM_PORT=9000 NGINX_SSL_PATH=./nginx/ssl/NGINXのポート番号を80 -> 8888に変更しました
Apacheのポート番号とダブらないようにするためです2 コンテナの起動
コンテナを起動します
docker-compose up -d nginx mysql phpmyadminここで8.0 -> 5.7にバージョンを変えた場合、MySQLのコンテナだけ起動されないという不具合が発生します。その時はDATA_PATH_HOSTで設定したフォルダを綺麗にして、イメージを作成し直す必要があります
対処法
① パス確認
$ cat .env | grep DATA_PATH_HOST
自分の場合は DATA_PATH_HOST=~/.laradock/data が表示されました
② パス、イメージ、コンテナを消去
rm -rf ~/.laradock/data/mysql
docker rmi laradock_mysql -f
docker rmi mysql -f
③ mysqlをビルドし直し
docker-compose build --no-cache mysql
④ docker ps でちゃんと動いているか確認しましょう3 Laravelプロジェクトの作成
workspaceに入って
$ docker exec -it laradock_workspace_1 bashLaravelプロジェクトの作成
生成後、sampleapp/Laravel/wikiLearns 内にディレクトリwikiLearnsが出来るので、これをsample/Laravelに置き直してください(何かここ方法があるはず)# composer create-project laravel/laravel wikiLearns(任意のアプリ名)workspaceから出ます
# exit設定の変更をするために一時停止
$ docker-compose stopAPP_CODE_PATH_HOST=../をAPP_CODE_PATH_HOST=../laravel/wikiLearns(自分の作ったディレクトリに対するLaradock起点での任意のパス)に書き換えてください
laradock.envAPP_CODE_PATH_HOST=../laravel/wikiLearns // ../コンテナ再起動
$ docker-compose up -d nginx mysqlブラウザでhttp://localhost:8888/ につなぐと例の画面が出てくるはずです。(出てこない場合は多分APP_CODE_PATH_HOSTのパス間違い)
4 MySQLへの接続
ハマった点2の説明です
LaradockのMySQLに接続したい時、
Laravel.envDB_CONNECTION=mysql DB_HOST=mysql // 127.0.0.1 DB_PORT=3306 DB_DATABASE=wikiLearns DB_USERNAME=homestead DB_PASSWORD=secretLaravelのDB_HOSTを127.0.0.1 -> mysqlに変更すれば接続できるはず...なんですが、PDOException::("SQLSTATE[HY000] [2002] Connection refused")が出てきます。このエラーはMySQLに認証されていないユーザーで接続しようとした時に発生します。MySQLのコンテナに入って新たにユーザー生成しましょう
1 ユーザー生成
「laradockのworkspaceコンテナからmysqlコンテナに接続」します。そうするとworkspaceからMySQLに接続してマイグレーション等ができるようになります
まずdocker inspectでworkspaceのIPアドレスを確認しましょう$ docker-compose up -d nginx mysql $ docker ps (これでworkspaceのコンテナIDを見られる) $ docker inspect be68295513a3(workspaceのIPアドレス)下の方にIPアドレスが書いてあります
"Gateway": "172.20.0.1", "IPAddress": "172.20.0.3", <- これ "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:14:00:03", "DriverOpts": nullMySQLコンテナに入ります
$ docker-compose exec mysql bash # mysql -u root -p # (パスワードはLaradockの.envのMYSQL_ROOT_PASSWORDを見る デフォルトはroot)データベースを作成
> create database wikiLearns(任意の名前);ユーザー作成
> create user 'root(任意の名前)'@'172.20.0.3(workspaceのIPアドレス)'identified by 'secret(任意のパスワード)'; > grant all privileges on . to 'root'@'172.20.0.3';2 .env編集
MySQLを出てLaradock、Laravelの.env編集
laradock.envMYSQL_VERSION=5.7 MYSQL_DATABASE=wikiLearns(作ったデータベース名) MYSQL_USER=root(作ったユーザー名) MYSQL_PASSWORD=secret(設定したパスワード) MYSQL_PORT=3306 MYSQL_ROOT_PASSWORD=root MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-initdb.dLaravel.envDB_CONNECTION=mysql DB_HOST=mysql // 127.0.0.1 → mysql DB_PORT=3306 DB_DATABASE=dockapp(Laradockと同じに) DB_USERNAME=root(Laradockと同じに) DB_PASSWORD=secret(Laradockと同じに)dockerを停止して再起動すればマイグレーションができます
$ docker-compose up -d nginx mysql $ docker exec -it laradock_workspace_1 /bin/bash $ php artisan migrateこれでdockerコンテナを立ち上げてlaravelを利用できるようになりました
- 投稿日:2019-10-23T16:49:08+09:00
DockerでReact + Swagger 環境を作ろう
現在業務でReactを使用しているのですが、事前に勉強する際にDocker環境を作成していたので、それを共有します。
ちなみにSwagger環境に関しては、自分で作成してうまくいかなかったので、上司が作成した環境を参考にさせてもらいました。感謝です前提
- Docker導入済み
- docker-composeコマンドが使用できる
事前準備
今回は4つのコンテナを使用。
- node...Reactのコードを実行するコンテナ
- swagger-editor...Swagger Editorのコンテナ
- swagger-api...Swagger定義ファイルから生成されたコードを実行するコンテナ
- swagger-nginx...swagger-apiの内容を配信するアプリケーションサーバのコンテナ(nginxをさらに高性能に使えるようにしたopenrestyを使用)
これらのDockerfileや必要な設定ファイルを用意していきます。
ちなみに作成後のディレクトリは以下のようになります。例 React(プロジェクトフォルダ) ├─ docker | ├─ nginx | | ├─ swagger.conf | ├─ node | | ├─ Dockerfile | ├─ swagger-api | ├─ Dockerfile | ├─ swagger.json ├─ docker-compose.ymlnginx/swagger.conf
nginx(openresty)の設定を記述します。
ここでCORSに関する設定をしておかないと、React側からaxiosでリクエストする際にエラーになってしまいます。
(自分が最初環境を作ろうとしたときに、ここでつまづいていました。今も設定に関しては疎いです...。)server { listen 80; server_name localhost; location /docs/ { proxy_pass http://swagger-api:8000/docs/; } location / { if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Headers 'X-Requested-With, Authorization, Origin, Accept, Content-Type'; add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE'; add_header Access-Control-Max-Age 86400; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Expose-Headers Set-Cookie; add_header Content-Type 'text/plain charset=UTF-8'; add_header Content-Length 0; return 204; } proxy_pass http://swagger-api:8000; add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Credentials true always; add_header Access-Control-Expose-Headers Content-Disposition; } }node/Dockerfile
Facebook公式のReactプロジェクトを作成するCLIツールである
create-react-appを使用するので、インストールしておきます。FROM "node:12-alpine" WORKDIR /usr/src/app/ RUN yarn global add create-react-appswagger-api/Dockerfile
Swagger定義ファイルをもとにコードを生成する
Swagger Codegenをインストールして、実際にnode.jsのコードを生成しています。FROM openjdk:8-jdk-alpine ARG CLI_VERSION=2.4.5 RUN wget http://central.maven.org/maven2/io/swagger/swagger-codegen-cli/${CLI_VERSION}/swagger-codegen-cli-${CLI_VERSION}.jar -O /swagger-codegen-cli.jar RUN apk --update add bash nodejs npm && rm -rf /var/cache/apk/* ADD swagger.json swagger.json RUN java -jar /swagger-codegen-cli.jar generate -l nodejs-server -i swagger.json -o src && \ cd src && npm install CMD ["java", "-jar", "/swagger-codegen-cli.jar"]swagger-api/swagger.json
Swagger定義ファイルです。
ここでは簡単に1つだけAPIを定義しています。{ "swagger": "2.0", "info": { "description": "テスト用API", "version": "1.0.0", "title": "Swagger test API設計書", "contact": {}, "license": { "name": "" } }, "host": "localhost:8000", "basePath": "/", "tags": [ { "name": "User", "description": "User Controller" } ], "paths": { "/user": { "get": { "tags": [ "User" ], "summary": "ユーザ情報取得", "description": "ユーザ情報を取得する。", "operationId": "doGetUsingGET", "consumes": [ "application/json" ], "produces": [ "application/json" ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/UserGetOut" } }, "400": { "description": "バリデーションエラー", "schema": { "$ref": "#/definitions/ValidationErrorsOut" } }, "500": { "description": "想定外のエラー", "schema": { "$ref": "#/definitions/ErrorInfo" } } } } } }, "definitions": { "UserGetOut": { "type": "object", "required": [ "userId", "name", "kana" ], "properties": { "userId": { "type": "string", "example": "abc001", "description": "ユーザID" }, "name": { "type": "string", "example": "山田 太郎", "description": "名前" }, "kana": { "type": "string", "example": "ヤマダ タロウ", "description": "カナ" } } }, "ValidationError": { "type": "object", "required": [ "itemName" "code", "content" ], "properties": { "itemName": { "type": "string", "example": "userId", "description": "項目名" }, "code": { "type": "string", "example": "NotBlank", "description": "code" }, "content": { "type": "string", "example": "必須項目が設定されていません。", "description": "content" } } }, "ValidationErrorsOut": { "type": "object", "required": [ "validationInfo" ], "properties": { "validationInfo": { "type": "array", "description": "バリデーション情報", "items": { "$ref": "#/definitions/ValidationError" } } } }, "ErrorInfo": { "type": "object", "required": [ "code", "content" ], "properties": { "code": { "type": "string", "example": "exception.errors.unexpeced.exception", "description": "エラーコード" }, "content": { "type": "string", "example": "システムエラーが発生しました。誠に恐れ入りますが、初めからやり直して下さい。", "description": "メッセージ" } } } } }docker-compose.yml
今回使用する4つのコンテナ定義を書いていきます。
なお、nodeのenvironmentのCHOKIDAR_USEPOLLING=trueはホットリロードを有効化にするものです。version: "3" services: node: build: ./docker/node environment: - NODE_ENV=development - CHOKIDAR_USEPOLLING=true volumes: - ./app/:/usr/src/app tty: true stdin_open: true ports: - "3000:3000" swagger-editor: image: swaggerapi/swagger-editor ports: - "8081:8080" swagger-api: build: ./docker/swagger-api working_dir: /src command: node index.js swagger-nginx: image: openresty/openresty:alpine ports: - 8000:80 depends_on: - swagger-api volumes: - ./docker/nginx/swagger.conf:/etc/nginx/conf.d/default.conf:roコンテナの作成と起動
コンテナのビルド
$ docker-compose buildコンテナをバックグラウンドで起動
$ docker-compose up -dReactプロジェクト作成と起動
1.コンテナの中に入る
$ docker-compose exec node sh2.プロジェクトのひな型作成
$ create-react-app .これでプロジェクトのひな型が作成されます。
この時点でのディレクトリ構成は以下のようになります。例 React(プロジェクトフォルダ) ├─ app | ├─ node_modules | | ├─ (各種パッケージ) | ├─ public | | ├─ favicon.ico | | ├─ index.html | | ├─ logo192.png | | ├─ logo512.png | | ├─ manifest.json | | ├─ rebots.txt | ├─ src | | ├─ App.css | | ├─ App.js | | ├─ App.test.js | | ├─ index.css | | ├─ index.js | | ├─ logo.svg | | ├─ serviceWorker.js | ├─ .gitignore | ├─ package.json | ├─ README.md | ├─ yarn.lock ├─ docker | ├─ nginx | ├─ swagger.conf | ├─ node | ├─ Dockerfile | ├─ swagger-api | ├─ Dockerfile | ├─ swagger.json ├─ docker-compose.yml3.サーバの起動
$ yarn start4.ブラウザでアクセス
localhost:3000にアクセスして、以下のような画面になればOKです。
ちなみにホットリロードを有効化にしているため、コードを変更して保存すると即座に反映されます。
なお、毎回コンテナの中に入ってサーバを起動するのが面倒な場合は、nodeのDockerfileの末尾に以下を追記してビルドしなおせば、次回からはコンテナ起動時にサーバも一緒に起動してくれます。
CMD ["yarn", "start"]Swagger
Swagger Editor
localhost:8081にアクセス。
左側がエディタ、右側が定義をもとにしたドキュメントになっています。Swagger定義ファイルを読み込む場合は、File→Import Fileからインポートできます。
なお、エディタ上から定義をもとにしたコードを生成することもできます。※注意点
エディタ上の変更は自動で保存されますが、インポートしたファイル自体を保存までは行ってくれません。
エディタで変更した定義ファイルをアプリケーションサーバに反映させたい場合は、File→Convert and save as JSONでファイルをダウンロードし、React(プロジェクトフォルダ)/docker/swagger-api配下に設置して、コンテナをビルドしなおす必要があります。Swagger UI
Swagger Codegenを使用してコードを生成すると、あわせてドキュメントも作成してくれています。
localhost:8000/docsにアクセスすることで確認できます。
ちなみに最初はSwagger UIのコンテナをまた別で立ち上げていたのですが、参照するSwagger定義ファイルを編集しているうちに、ファイルに間違いがない状態でもなぜかエラーが出てしまい、いまいち使えなくなってしまいました。(Swagger Editor上で何もエラーが出ていない状態で出力したファイルでもエラーになりました)
Swaggerのサーバ
localhost:8000でアクセスできます。
今回はSwagger定義ファイルで定義しているAPIにリクエストしてみます。ブラウザからアクセス
GETのAPIなので、直接ブラウザからアクセスしてもレスポンスが返ってきます。
localhost:8000/userにアクセスすると以下のようになります。
axiosでアクセス
まずはコンテナの中に入り、yarnでaxiosをインストール。
$ yarn add axiossrc/App.jsを以下のように修正。
(あまりいい書き方ではないと思いますが、とりあえず動作確認用のコードです)
import React from 'react'; import logo from './logo.svg'; import './App.css'; import axios from 'axios'; // 追記 function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> {/* 以下を追記 */} <button onClick={ () => axios.get('http://localhost:8000/user') .then((result) => { console.log(result) }) .catch((error) => { console.log(error) }) } > APIリクエスト </button> {/* ここまで追記 */} </header> </div> ); } export default App;
localhost:3000にアクセスし、APIリクエストのボタンを押すとaxiosのリクエストが実行されます。
コンソールに出力しているので、Developer Toolsで確認すると以下のようにデータが取得できているのが確認できるかと思います。
その他必要なもの
使用しているエディタにReactに関する拡張を導入するとより開発しやすくなります。
VSCode拡張
Full React/React Native/React Router/Redux/GraphQL/ES7/Testing/PropTypes snippets
名称にある通り、各種のスニペットが使用でき、慣れてくるとコーディングが捗るかと思います。
(自分はあまり使いこなせてなかったりします...)Chrome拡張
React Developer Tools
Developer ToolsにComponentsとProfilerタブが追加されます。
コンポーネントの階層や、propsやstateの中身を確認したりすることができデバッグがしやすくなります。
Chromeウェブストアからインストール
ChromeのReact Developer Toolsアイコンを右クリックして、「拡張機能を管理」へ
「ファイルの URL へのアクセスを許可する」をONにする
静的解析ツールであるESLintも導入した方がいいとは思うのですが、VSCode上で動かすのがうまくいかなかったので今回は書いていません。
(いずれちゃんと設定できたら書くかも...)参考
- 投稿日:2019-10-23T15:55:05+09:00
Vue.js 編 - 初心者こそ、Docker を使おう!
簡単なTodo アプリを作りましょう
- オリジナルはdotinstall さんの vue.js のtodoアプリをアレンジしたものですので詳しくはそちらをみてください。
今回は、Vue.js を使って、Todoに必要な処理の練習をします。
Todo タスクを追加してみましょう。
lang指定でts,stylusを指定していますが、typescript,stylus css用ですが、実際つかっているのは、javascript,cssです。stylusにすると、混在できますのでstylusを使っています。typescriptの混在できますので、型つけたければつければいいかと思います。Vue.js は、input周りは、簡単に処理できるのがいいですね。
src/MyApp.vue<template lang="pug"> div.container Todo </template> <script lang="ts"> import Vue from 'vue'; import Hello from './Hello.vue'; import Todo from './Todo.vue'; export default Vue.extend({ components: { Todo, } }) </script> <style lang="stylus"> body { font-size: 16px; font-family: Verdana, Geneva, Tahoma, sans-serif; } .container { width: 300px; margin: auto; } h1 { font-size: 16px; border-bottom: 1px solid #ddd; padding: 16px 0; } li { line-height: 1.5; } input[type="text"] { padding: 2px; } .done color gray text-decoration line-through </style>
src/Todo.vue<template lang="pug"> div ul li(v-for="todo in todos") | {{ todo }} form( @submit.prevent="addItem" ) input(type="text" v-model="newItem") input(type="submit" value="Add") </template> <script lang="ts"> import Vue from 'vue' export default Vue.extend({ data() { return({ newItem: '', todos: [ "task 0", "task 1", "task 2", ] }) }, methods: { addItem() { this.todos.push(this.newItem); this.newItem = ''; } } }) </script>
- コンテナ(uname linux でしたね)
uname cd src npx parcel --hmr-port 1235 --hmr-hostname localhost index.pugdelete / checkbox
削除もチェックボックスも実装が楽ですね。
id追加しましたが、使っていません(笑) index指定で削除していますが、まずければidに変えようと思いましたが、問題なさそうなので、使っていません。
src/Todo.vue<template lang="pug"> div ul( v-if="todos.length" ) li(v-for="todo, index in todos") input(type="checkbox" v-model="todo.isDone") span( :class="{done: todo.isDone }" ) {{ todo.title }} : {{ todo.isDone }} button( @click="deleteItem(index)" ) Delete ul( v-else ) | Nothing todo form( @submit.prevent="addItem" ) input(type="text" v-model="newItem") input(type="submit" value="Add") </template> <script lang="ts"> import Vue from 'vue' export default Vue.extend({ data() { return({ newItem: '', todos: [ { id: 0, title: 'Task 0', isDone: false }, { id: 1, title: 'Task 1', isDone: false }, { id: 2, title: 'Task 2', isDone: true }, ] }) }, methods: { addItem() { const newItem = { id: new Date().getTime().toString(36), title: this.newItem, isDone: false, } this.todos.push(newItem); this.newItem = ''; console.log(newItem); }, deleteItem(index) { this.todos.splice(index, 1) } } }) </script>複数削除
完了していないタスクは、computed で常に集計できるので、それを新しい配列にすれば、結果的に完了タスクを削除したことになりますね。
Todo.vue<template lang="pug"> div h1 | todo span ( {{ remaining.length }} : {{ todos.length }} ) button( @click="doneItemsPurge" ) Purge ul( v-if="todos.length" ) li(v-for="todo, index in todos") input(type="checkbox" v-model="todo.isDone") span( :class="{done: todo.isDone }" ) {{ todo.title }} : {{ todo.isDone }} button( @click="deleteItem(index)" ) Delete ul( v-else ) | Nothing todo form( @submit.prevent="addItem" ) input(type="text" v-model="newItem") input(type="submit" value="Add") </template> <script lang="ts"> import Vue from 'vue' export default Vue.extend({ data() { return({ newItem: '', todos: [ { id: 0, title: 'Task 0', isDone: false }, { id: 1, title: 'Task 1', isDone: false }, { id: 2, title: 'Task 2', isDone: true }, ] }) }, methods: { doneItemsPurge() { this.todos = this.remaining }, addItem() { const newItem = { id: new Date().getTime().toString(36), title: this.newItem, isDone: false, } this.todos.push(newItem); this.newItem = ''; console.log(newItem); }, deleteItem(index) { this.todos.splice(index, 1) } }, computed: { remaining() { return this.todos.filter( todo => { return !todo.isDone }) } } }) </script>データの永続化
初心者むけでは大体
localStorageを使う例が多いので、 ここでは、Firebaseの DBFireStoreを使ってみようかと思います。
FireStore dbは、googoleのアカウントがあれば、利用できますので、firebase consoleで検索してみてください。 ここでは、プロジェクトの作成やfireStoreの有効にする方法は説明しませんので、利用出来る前提で始めていきます。
fireStore の 読み書きルール はすべて true の テストモードで行っています。
- ファイル構成です。
├── Dockerfile ├── docker-compose.yml ├── firebase.js └── src ├── Hello.vue ├── MyApp.vue ├── Todo.vue ├── dist ├── index.js ├── index.pug ├── package.json └── yarn.lockルードディレクトリに
firebase.jsを作っていますので、そこにfirebaseのconfigをコピペしてください。
firebase.jsexport const config = { apiKey: "", authDomain: "", databaseURL: "", projectId: "", storageBucket: "", messagingSenderId: "", appId: "", measurementId: "" };MyApp.vue はほとんど変わっていませんが一応記載します。
src/MyApp.vue<template lang="pug"> div.container //- Hello Todo </template> <script lang="ts"> import Vue from 'vue'; import Hello from './Hello.vue'; import Todo from './Todo.vue'; export default Vue.extend({ components: { Todo, Hello, } }) </script> <style lang="stylus"> body { font-size: 16px; font-family: Verdana, Geneva, Tahoma, sans-serif; } .container { width: 700px; margin: auto; } h1 { font-size: 16px; border-bottom: 1px solid #ddd; padding: 16px 0; } li { line-height: 1.5; } input[type="text"] { padding: 2px; } .done color gray text-decoration line-through </style>Todo.vue は、
fireStore対応で大幅に変わっています。
リファクタリングもしていないので、見苦しい感じが残っていますが、実装の苦労の跡が見えていいのではないでしょうか(笑)
なるべく、fireStoreの機能を使って実装しようとしているので、データのやり取りは、fireStoreを毎回介して行っています。
マウントとアンマウントの時にfireStoreにデータを渡したほうが動作が軽く楽かもしれませんが
fireStoreの練習には、こちらのほうがいいかと思います.ラグが気になりますが、追加、削除、完了、未完了、一括削除ができているのOK でしょう。(笑)
async / await に慣れていない人へ
DB を使うと処理が非同期になるため、async / await を使っていますが、asyce/await に慣れていない人に一言いうと、処理に時間がかかりそうだと思うものの前に,すべて
awaitを 付けていけばいいです。
今回で言えば、データの読み書きでfirestoreに対してのと命令を書いた場合にあたります。
付けていないと、ほしいデータが入る前に次の処理が走ってしまって、空処理になるのを防いでいます。
ですから、時間がかかると思ったら、awaitを処理の前につけてください。
awaitを使うとき、親要素にasyncという呪文が必要なので、これを関数式に付けます。
awaitをつけたけれど、親要素がない場合は、そのあたりの処理一体を、関数にまとめてしまえばいいです。
そうすれば、非同期処理はできているはずです。
src/Todo.vue<template lang="pug"> div h1 | todo span ( {{ remaining.length }} : {{ todos.length }} ) button( @click="doneItemsPurge" ) Purge form( @submit.prevent="addItem" ) input(type="text" v-model="newItem") input(type="submit" value="Add") ul( v-if="todos.length" ) li(v-for="todo, index in todos") //- input(type="checkbox" v-model="todo.isDone") input(type="checkbox" @click="checkboxChange(index)" :checked="todo.isDone") span( :class="{done: todo.isDone }" ) {{ todo.title }} : {{ todo.isDone }} : {{ todo.date }} button( @click="deleteItem(index)" ) Delete ul( v-else ) | Nothing todo </template> <script lang="ts"> import * as firebase from 'firebase/app'; import 'firebase/firestore'; import { config } from '../firebase'; firebase.initializeApp(config); const db = firebase.firestore() const collection = db.collection('todos') import Vue from 'vue' export default Vue.extend({ data() { return({ newItem: '', todos: [], itemsId: [], storeItem: {}, state: [], }) }, watch: { state: { // 更新チェック されたら、実行 handler: async function(){ const queryItems = await collection.orderBy("created_at", "desc").get() const qureyItemsData = queryItems.docs.map( item => item.data()) const qureyItemsId = queryItems.docs.map( item => item.id ) this.todos = qureyItemsData; this.itemsId = qureyItemsId; }, deep: true }, todos: { handler: async function(){ }, deep: true } }, methods: { async checkboxChange(index) { let isDoneState = Boolean; const item = await collection.doc(this.itemsId[index]) const isDone = await item.get() .then(function(doc) { isDoneState = doc.data().isDone }) .catch( err => { console.log(err); }) const changeItem = await item.update({ isDone: !isDoneState, }) this.state = ["checkboxUpdate"] }, async deleteItem(index) { const item = await collection.doc(this.itemsId[index]).delete() this.state = ["delete"] }, addItem() { this.storeItem = { id: new Date().getTime(), date: new Date().toLocaleString("ja"), title: this.newItem, isDone: false, created_at: firebase.firestore.FieldValue.serverTimestamp(), } const item = collection.add(this.storeItem); this.newItem = ''; this.state = ["addItem"] // 状態更新通知用 }, async doneItemsPurge() { // this.todos = this.remaining const itemsQuery = await collection.where("isDone", "==" , true) .get() .then(function(querySnapshot) { querySnapshot.forEach(function(doc) { const item = collection.doc(doc.id).delete(); console.log(item); }); }) .catch(function(error) { console.log("Error getting documents: ", error); }) this.state = ["purge"] // 状態更新通知用 }, }, computed: { remaining() { return this.todos.filter( todo => { return !todo.isDone }) } }, async mounted() { const query = await collection.get() const items = query.docs.map( item => item.data()) const itemsId = query.docs.map( item => item.id) this.todos = items; this.itemsId = itemsId; this.state = items; } }) </script>これで、Vue.js での練習は、終了です。
お疲れ様でした。次回は, この環境で、React を使ってみたいと思います
- 投稿日:2019-10-23T12:24:48+09:00
AWSのDNS障害でDebianパッケージがインストールできなかった話
やろうとしたこと
Dockerファイルをビルドしようとしていました。
FROM php:7.1.11-fpm WORKDIR /var/local RUN apt-get update && apt-get install -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget ...エラー発生
Step 3/13 : RUN apt-get update && apt-get install -y apt-transport-https lsb-release ca-certificates wget ---> Running in 50a658d96e1f Get:1 http://security.debian.org jessie/updates InRelease [44.9 kB] Err http://deb.debian.org jessie InRelease Err http://deb.debian.org jessie-updates InRelease Err http://deb.debian.org jessie Release.gpg Could not resolve 'cdn-fastly.deb.debian.org' Err http://deb.debian.org jessie-updates Release.gpg Could not resolve 'cdn-fastly.deb.debian.org' Get:2 http://security.debian.org jessie/updates/main amd64 Packages [893 kB] Fetched 938 kB in 4s (192 kB/s) Reading package lists... W: Failed to fetch http://deb.debian.org/debian/dists/jessie/InRelease W: Failed to fetch http://deb.debian.org/debian/dists/jessie-updates/InRelease W: Failed to fetch http://deb.debian.org/debian/dists/jessie/Release.gpg Could not resolve 'cdn-fastly.deb.debian.org' W: Failed to fetch http://deb.debian.org/debian/dists/jessie-updates/Release.gpg Could not resolve 'cdn-fastly.deb.debian.org' W: Some index files failed to download. They have been ignored, or old ones used instead. Reading package lists... Building dependency tree... Reading state information... Package lsb-release is not available, but is referred to by another package. This may mean that the package is missing, has been obsoleted, or is only available from another source E: Package 'lsb-release' has no installation candidate The command '/bin/sh -c apt-get update && apt-get install -y apt-transport-https lsb-release ca-certificates wget' returned a non-zero code: 100 make: *** [build] Error 100原因調査
deb.debian.orgのサーバーが死んだのかな?と思いきや、エラーメッセージに下記を発見。
Could not resolve 'deb.debian.org'ネームサーバー変わったのかなと思っていたら、社内のエンジニアからSlackが飛んできました。
AWSでDNS周りの障害が起きていたみたいです。https://www.theregister.co.uk/2019/10/22/aws_dns_ddos/
その障害によって、deb.debian.orgの名前解決ができず、パッケージのダウンロードができなくなっていたんですね。
障害復旧後
下記のステータスを、AWSで確認しました。
[RESOLVED] Intermittent DNS Resolution Errors Between 10:30 AM and 6:30 PM PDT, we experienced intermittent errors with resolution of some AWS DNS names. Beginning at 5:16 PM, a very small number of specific DNS names experienced a higher error rate. These issues have been resolved.その後再ビルドすると、無事にdebianパッケージもインストールされ、ビルドできました!
考察
おそらくdeb.debian.orgはRoute53あたりを使っているんでしょうか。
今後debianパッケージ取得の際に名前解決関係のエラーが出たら、AWSの障害を疑ってみることも一つの手ですね。
- 投稿日:2019-10-23T12:23:52+09:00
GCPのGCRとAWSのECR併用時に no basic auth credentials エラー
環境
- MacOS
- docker desktop community 2.1.0.1(37199) stable
- aws-cli/1.16.166 Python/2.7.15 Darwin/18.7.0 botocore/1.12.156
事象
以下のコマンドでECRにログインする。
$ $(aws ecr get-login --no-include-email --region ap-northeast-1)そして、docker buildしようとすると以下のようなエラーメッセージが出た。
no basic auth credentials原因
結論から言うと、その前にGCPのGCRにログインしていたことが原因だった。
~/.docker/config.jsonの中身を見ると、以下のようにECRとGCRの設定が混在していた。{ "auths": { "xxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com": {}, "asia.gcr.io": {}, "eu.gcr.io": {}, "gcr.io": {}, "https://asia.gcr.io": {}, "https://eu.gcr.io": {}, "https://gcr.io": {}, "https://marketplace.gcr.io": {}, "https://staging-k8s.gcr.io": {}, "https://us.gcr.io": {}, "marketplace.gcr.io": {}, "staging-k8s.gcr.io": {}, "us.gcr.io": {} }, "HttpHeaders": { "User-Agent": "Docker-Client/19.03.1 (darwin)" }, "credsStore": "desktop", "credHelpers": { "asia.gcr.io": "gcloud", "eu.gcr.io": "gcloud", "gcr.io": "gcloud", "marketplace.gcr.io": "gcloud", "staging-k8s.gcr.io": "gcloud", "us.gcr.io": "gcloud" } }そこで
~/.docker/config.jsonを削除した後、再度$(aws ecr get-login --no-include-email --region ap-northeast-1)によりログインするとうまく行った。うまくいったときの
~/.docker/config.jsonは以下のようであった{ "auths": { "xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com": {} }, "HttpHeaders": { "User-Agent": "Docker-Client/19.03.1 (darwin)" }, "credsStore": "osxkeychain" }もっとスマートな回避方法はあると思いますが、分かり次第追記します。
一旦内容共有まで。
- 投稿日:2019-10-23T12:22:24+09:00
dockerを使って構築した、vue.jsのアプリがデプロイした際に動かなくなった話
dockerのマルチステージビルドを使って構築した、vue.jsのアプリがデプロイした際にローカル環境では発生しないエラーが実際のサーバー上でだけ発生する事象が発生しました。
通常通りのやり方だと気づけなかったポイントなので、共有しようと思います。マルチステージビルドとは?
マルチステージビルドはdockerのimageを作成する際、
docker build時にだけ立ち上がるコンテナでそこでできた生成物を実際のイメージに配置するみたいなことができます。
どこかの環境で(jenkins等)node.jsをbuildしてその生成物を配置するみたいな必要がなくなりdockerだけで完結できるようになるのでVue.js の公式も推奨しているデプロイ方法になります。ハマったポイント
ローカルで
npm installしたときに生成されるnode_modulesと サーバーのコンテナ上で生成されるnode_modulesに差分があり、ローカル環境でうまく実行できていたものがサーバーのコンテナ上ではうまく実行されずエラーになってしまった。原因
ローカル環境で
Vue.jsの開発をするときは、npm run dev等で ローカルのサーバーを立てて開発することが多いと思います。
そのため、node_modulesやdistファイルは`同じプロジェクト内にローカル環境だけは共存している形になると思います。
ローカルで以下のようなdockerfileをもとにvue.js のプロジェクトをbuildしたのですが、DockerfileCOPY ./vue ./ RUN npm install RUN npm run buildこのときの
COPYの挙動ではローカルに含まれるnode_modulesやdistファイルも一緒にコンテナ内に配置されてしまいます。
そのため、RUN npm installが実行されても、新規でnode_modulesが生成されることがなく baseimageのversionとローカルのversionの差分等があるとうまく生成されないというような事象が発生してしまっていました。対処方法
.dockerignoreと呼ばれるdockerから無視させるファイルリストを追加する方法があるので、このファイルに以下のように無視ファイルの対象として追加する。
./vue/dist/ ./vue/node_modules/※ディレクトリ階層は使っているものに合わせてください。
追加することで、
docker build時は毎回新規でnpm installが走るようになるので、サーバーだろうがローカル環境だろうが同じ状態にすることができ、問題を解決することができました。さいごに
今回のミスは、たまたまアプリを起動するときに出てくるエラーで動作の一部ができなくなるという感じのエラーではなく気づくことができましたが、ほんとに一部でしか使っていない動作でのエラーとかだとリリースしてからエラーが発生する等の問題になりかねないので注意が必要ですね。
あと、今回差分が発生してしまった一番の大きな原因は dockerの
baseimageのversionがnode:6.4とかだったのに対して、ローカル環境が10くらいになっていたことだったので、プロジェクトの生成からdockerのコンテナ内でやったほうが幸せになれると思いました。 Rubyとかは記事とかそこそこあるんですけどね…
- 投稿日:2019-10-23T10:40:19+09:00
Dockerfileではまったことや最近したことまとめ
docker buildをしていてうまく動かないことや新たにもった知見などがあったのでまとめる。
ARG
外部から値を注入できる
下記Dockerdileから一部抜粋
ARG copy_path # 使うとき COPY ${copy_path} /path/to/usebuildするとき
docker build ./ --build-arg copy_path=./scriptADD
COPYとの違いとして、解凍、展開をしてくれると記載されていることが多いが、zipファイルは解凍されないので注意。
解凍、展開はtar、gzの場合に行われる。docker build時の注意点
context
一番ハマったやつ
sample |- docker | |- web | |- Dockerfile | |- config |- web |- nginx.conf上記のようなディレクトリ構造でプロジェクトルートにてdokcer buildを行う際、
docker build -f docker/web/Dockerfile docker/webとするとnginx.confを参照(ADDやCOPY)することはできなくなる。これは
docker/webと指定している部分(context)で参照スコープを絞っているため、docker/webよりも上位階層から枝分かれしたディレクトリを見れなくなってしまうからということらしい。言われてみるとなるほど!となるんだけど別リポジトリのDockerfileやMakefileをコピってきてちょちょで使おうとするとハマりやすそうなところだったのでまとめてみました。
以上
- 投稿日:2019-10-23T09:57:10+09:00
Windows HomeでDockerを使うためにAmazon EC2を利用した話
はじめに
本記事は,「量子アニーリングの基礎」を読む,という勉強会(読書会)での不都合解消のために書いたものです。
不都合
@kaizen_nagoya さんが用意してくれている検証用のDockerコンテナ があるのですが,手持ちのノートPCがWindows HomeであったためDockerがインストールできません。(Homeでも頑張れば使えるようにできるようですが面倒くさい)
なので,Amazon EC2にLinuxインスタンスを立ててDocker使えるようにすればいいじゃない,と思いつき,動かすまでの作業を記録することにしました。Amazon EC2
初めて使う場合料金が心配かと思いますが,勉強会用に利用するだけなら無料枠で十分です。
ここにアカウント作成からインスタンスの起動までに必要なことが一通り書いてあります。Linuxインスタンスとの接続はここに手順が記されています。
ちなみに,私の場合インスタンスの種類はubuntuを選択しました。(単に自分が使い慣れてるディストリビューションだったため)
接続手段としてPuTTYを選びました。
ファイル転送ソフトはWinSCPを選びました。
ubuntuへのDockerインストールはこの記事「Ubuntuにdockerをインストールする」を参考にしました。主な作業内容
・アカウントを作成する
・インスタンスを起動する
・プライベートキーの作成と保存
・インスタンスIDの把握
・パブリックDNSを把握する
・デフォルトユーザー名の把握
・接続端末(TTY)を用意する
・PuTTYの準備
・PuTTYの場合は,プライベートキーの変換
・PuTTYの接続設定
・ファイル転送できるようにする
・インスタンスへの接続
・Dockerのインストール
・Dockerコンテナの取得参考文献
Qiita記事「docker(28) Openjij チュートリアルをdockerで」
Qiita記事「Ubuntuにdockerをインストールする」
- 投稿日:2019-10-23T09:57:10+09:00
Windows10 HomeでDockerを使うためにAmazon EC2を利用した話
はじめに
本記事は,「量子アニーリングの基礎」を読む,という勉強会(読書会)での不都合解消のために書いたものです。
不都合
@kaizen_nagoya さんが用意してくれている検証用のDockerコンテナ があるのですが,手持ちのノートPCがWindows10 Homeであったため
Dockerがインストールできません。HomeでもDocker Toolboxを使えば利用できるようになりますが,Windows10以前のバージョンを利用している方もいましたので,Amazon EC2にLinuxインスタンスを立ててDocker使えるようにすればいいじゃない,と思いつき,動かすまでの作業を記録することにしました。Amazon EC2
初めて使う場合料金が心配かと思いますが,勉強会用に利用するだけなら無料枠で十分です。
ここにアカウント作成からインスタンスの起動までに必要なことが一通り書いてあります。Linuxインスタンスとの接続はここに手順が記されています。
ちなみに,私の場合インスタンスの種類はubuntuを選択しました。(単に自分が使い慣れてるディストリビューションだったため)
接続手段としてPuTTYを選びました。
ファイル転送ソフトはWinSCPを選びました。
ubuntuへのDockerインストールはこの記事「Ubuntuにdockerをインストールする」を参考にしました。主な作業内容
・アカウントを作成する
・インスタンスを起動する
・プライベートキーの作成と保存
・インスタンスIDの把握
・パブリックDNSを把握する
・デフォルトユーザー名の把握
・接続端末(TTY)を用意する
・PuTTYの準備
・PuTTYの場合は,プライベートキーの変換
・PuTTYの接続設定
・ファイル転送できるようにする
・インスタンスへの接続
・Dockerのインストール
・Dockerコンテナの取得参考文献
Qiita記事「docker(28) Openjij チュートリアルをdockerで」
Qiita記事「Ubuntuにdockerをインストールする」






