20200319のdockerに関する記事は8件です。

クラウドネイティブでよく聞くサービス概要

CNCFとは

CNCF(Cloud Native Computing Foundation)とはinux Foundationのプロジェクトで、コンテナ技術の発展と、その進化に関連するテクノロジ業界の連携を支援するための団体。

https://labs.mobingi.com/cncf/

✨ Kubernetes

✨ containerd

✨Envoy

✨ Prometheus

✨ Grafana

✨Fluentd

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オフライン環境のDockerでAlfrescoを立ち上げる

概要

dokcer-composeとdockerイメージを取得し、オフライン環境で起動する。

  • オンライン環境作業

    • docker-composeの取得
    • dockerイメージをpullで取得
    • 取得したdockerイメージをtarで圧縮
  • オフライン環境作業

    • docker-composeの導入
    • dockerイメージを展開
    • docker-composeコマンドでコンテナ起動

オンライン環境作業

初めにdocker-composeを取得する。

## docker-composeをgitから取得
sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /tmp/docker-compose

## ファイル確認
$ ls -l /tmp/docker-compose
-rw-r--r-- 1 root     root       11750136 Mar 19 08:24 docker-compose

あわせて、必要な3つのイメージを取得する。

  • webcenter/rancher-alfresco:v5.1-201605-1
  • alpine
  • postgres:9.4
## webcenter/rancher-alfresco:v5.1-201605-1
$ docker pull webcenter/rancher-alfresco:v5.1-201605-1

## alpine
$ docker pull alpine

## postgres:9.4
$ docker pull postgres:9.4

## イメージ取得後の確認
$ docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
postgres                     9.4                 ed5a45034282        4 weeks ago         251MB
alpine                       latest              e7d92cdc71fe        2 months ago        5.59MB
webcenter/rancher-alfresco   v5.1-201605-1       c76b4794cf11        3 years ago         2.14GB

続いて、公式ドキュメントにある通り、dockerイメージをtarファイルに出力する。

## dockerイメージをtarにする
$ docker save postgres:9.4 webcenter/rancher-alfresco:v5.1-201605-1 alpine > alfresco.tar

## ファイル確認
$ ls -l alfresco.tar
-rw-rw-r-- 1 root root 2435766272 Mar 19 07:41 alfresco.tar

ここまでで取得した以下の2ファイルをオフライン環境へ配置する。

  • docker-compose
  • alfresco.tar

オフライン環境で作業

ここからはオフライン環境での作業になる。
まずは取得したファイルが配置してあることを確認する。

## 配置確認
$ ls -l /tmp
-rw-r--r-- 1 root root 11750136 Mar 19 08:24 docker-compose
-rw-rw-r-- 1 root root 2435766272 Mar 19 07:41 alfresco.tar

docker-composeの導入を行う。

## bin配下にdocker-composeを配置
$ sudo mv /tmp/docker-compose /usr/local/bin/

## 実行権限を付与
$ sudo chmod +x /usr/local/bin/docker-compose

## 導入確認(バージョンが表示されること)
$ docker-compose -v
docker-compose version 1.22.0, build f46880fe

docker-compose.ymlは以下に書かれていたもの参考に用意。

参考:【Docker】これは役に立つ!! docker-compose.ymlの例まとめ

docker-compose.yml
alfresco:
  environment:
    CIFS_ENABLED: 'false'
    FTP_ENABLED: 'false'
  tty: true
  image: webcenter/rancher-alfresco:v5.1-201605-1
  links:
  - postgres:db
  stdin_open: true
  ports:
  - 8081:8080/tcp
  volumes_from:
    - alfresco-data
alfresco-data:
  image: alpine
  volumes:
  - /opt/alfresco/alf_data
  net: none
  command: /bin/true
postgres:
  environment:
    PGDATA: /var/lib/postgresql/data/pgdata
    POSTGRES_DB: alfrescodb
    POSTGRES_PASSWORD: password
    POSTGRES_USER: alfrescouser
  tty: true
  image: postgres:9.4
  stdin_open: true
  volumes_from:
    - postgres-data
postgres-data:
  labels:
    io.rancher.container.start_once: 'true'
  image: alpine
  volumes:
  - /var/lib/postgresql/data/pgdata
  net: none
  command: /bin/true

私が使用しているオフライン環境では8080ポートが使用済みのため、ポートを8081へ変更している。

いよいよ、dokcerコンテナを起動する。
docker-compose.ymlが置いてある階層で以下のコマンドを実施する。

## コンテナ起動
$ docker-compose up -d
Starting alfresco_alfresco-data_1 ... done
Starting alfresco_postgres-data_1 ... done
Starting alfresco_postgres_1      ... done
Starting alfresco_alfresco_1      ... done

## コンテナ起動確認
$ docker-compose ps
          Name                        Command              State                                            Ports
----------------------------------------------------------------------------------------------------------------------------------------------------------
alfresco_alfresco-data_1   /bin/true                       Exit 0
alfresco_alfresco_1        /bin/sh -c /app/run.sh          Up       137/tcp, 138/tcp, 139/tcp, 21/tcp, 445/tcp, 7070/tcp, 8009/tcp, 0.0.0.0:8081->8080/tcp
alfresco_postgres-data_1   /bin/true                       Exit 0
alfresco_postgres_1        docker-entrypoint.sh postgres   Up       5432/tcp

最後に実際にアクセスしてみる。

ブラウザを開き、以下のアドレスを入力。
http://[オフライン環境のIPアドレス]:8081/share/page

初期ユーザ/初期パスワードはadmin/admin
login.png

以上で終了になります。

おわりに

Qiita初投稿でした!
アウトプットを全くしてこなかったので記事にしてみました。

余談

私はオンライン環境にAWSを使用していました。
EBS容量不足やエンドポイントの使い方など含めて、記事には出していない問題もいくつかありました。
あと、Markdown形式の文章も初めて書いたかも。
いい学習になったかも。

~おしまい~

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Raspberry Pi 3にDockerでfluentdを建ててみる

経緯

  • Raspberry Pi内部で動いているアプリケーションがエラーを吐いたらログをSlackに出したい
    • Raspiに直接fluentd入れるのは嫌なのでDocker化したい!

前提

  • Raspberry Piのセットアップは完了してる
  • 何らかのアプリケーションが既にRaspberry Pi上に存在する

手順

Dockerfileの準備

  • ポイントとしてはRaspberry PiとcompatibleなRubyイメージが必要
    • fluentd動かすにはRuby v2.4.0以上が必要らしい
  • slack通知したいのでfluent-plugin-slackを入れる
FROM lockitron/rpi-ruby:2.4.0

RUN apt-get update -y && \
    apt-get install -y ruby-dev g++ make && \
    gem install fluentd fluent-plugin-secure-forward fluent-plugin-slack && \
    apt-get remove --purge -y  $(apt-mark showauto) && \ 
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
    mkdir -p /fluentd/etc /fluentd/plugins

WORKDIR /home/ubuntu

COPY fluent.conf /fluentd/etc/
COPY plugins /fluentd/plugins/

EXPOSE 24224

CMD ["exec", "fluentd", "-c", "/fluentd/etc/fluent.conf", "-p", "/fluentd/plugins"]
  • fluentdの設定は以下の感じ
    • /ERROR|Error|error|NameError/ に引っ掛かる場合に通知する感じ
fluent.conf
<source>
  @id app
  @type tail
  read_from_head true
  # Raspberry PiのアプリケーションログをfluentdのDockerコンテナにマウントして、その先を指定する
  path /fluentd/logs/app/output.log
  pos_file /var/log/fluentd/logs/app/output.log.pos
  format none
  tag error_log_detail.app
</source>

# filter by error message
<filter error_log_detail.**>
  @type grep
  <regexp>
    key message
    pattern /ERROR|Error|error|NameError/
  </regexp>
</filter>

# post to slack
<match error_log_detail.**>
  @type slack
  webhook_url https://hooks.slack.com/services/xxxxx/xxxxx/xxxxx # slackのslack incoming webhooksを設定する
  channel raspi_health_check # 任意のslackチャネル
  username error-log
  flush_interval 10s
  color error
  icon_emoji :ghost:
</match>
  • 上記のDockerfileをbuildしてDockerHubにpushしておく

Raspberry PiにDockerをいれる

  • 以下の手順でRaspberry PiにDockerをインストールする
# Raspiにログインする
# Docker周りの必要なライブラリをインストールしてくれる
$ curl -sSL https://get.docker.com | sh
$ sudo usermod -aG docker pi
$ docker --version
#--> Docker version 19.03.8, build afacb8b
# 一度ログアウトする

作ったDockerコンテナをRaspberry Pi上で起動する

# Raspiにログイン
$ ssh pi@${raspiのIP}
# このDockerイメージは https://github.com/koska-devs/RasFluentd で管理してる
$ docker pull ${DockerHubのアップ先}
# マウントする先は適宜変える
$ docker run -d --name=rpi-fluentd -p 24224:24224 -v /home/pi/logs:/fluentd/logs ${DockerHubのアップ先}

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VisualStudio2017でリモートデバッグ

やること

ubuntu環境をdockerで構築し、VisualStudio2017からリモートデバッグを行います。

リモートデバッグを行うコンテナを用意

dockerfile
FROM ubuntu:16.04

# 各種インストール
RUN apt-get update
RUN apt-get install -y openssh-server sudo bash-completion g++ gdb gdbserver rsync git
# SSH用のディレクトリ作成
RUN mkdir /run/sshd
# ユーザーを追加
RUN useradd -m -s /bin/bash ubuntu && gpasswd -a ubuntu sudo
# パスワードを設定
RUN echo 'ubuntu:ubuntu' | chpasswd

# 22番ポートを公開
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
docker-compose
version: '2.3'
services:
  dev:
    build: .
    ports:
    - "2222:22"
    volumes:
    - ../volume:/tmp/data

イメージをビルド/コンテナを起動

$ docker-compose build
$ docker-compose up -d

SSH

$ docker exec -it docker_dev bash

VisualStudio

デバッグを行うプロジェクトを用意

  • 新規作成 > Visual C++ > クロスプラットフォーム > Linux
    • ない場合はインストーラから「C++によるLinux開発」を選択し、インストール

VisualStudio側の設定

  • 接続先の指定
    • ツール > オプション > クロスプラットフォーム > 接続マネージャー > 追加
      • ホスト名:リモート先のIP(localhost)
      • ポート:22番ポートにマッピングされているポート(2222)
      • ユーザー名:ゲストOSのユーザー名(ubuntu)
      • 認証の種類:パスワード
      • パスワード:上記で設定したパスワード(ubuntu)

()は上記で設定した場合の値

デバッグ

  • ソリューションのリビルドを実行
    • ビルド > ソリューションのリビルド
  • Linuxコンソールの表示
    • デバッグ > linux コンソール
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker で Ubuntu 環境を作り、Nuxt.js を動かしてみる

Prologue

Nuxt.js で作成したプロジェクトを Ubuntu 環境で build した際エラーが出ました。
このエラーはlocalでは起こらず、エラー内容の詳細を取得できるか試すため、Ubuntu の環境を作って確認しようとしたことがきっかけです。

ここではDockerの初期設定から簡単なNuxt.jsプロジェクトの作成までを行います。
結果としてエラーは環境とは関係なかったため、ここでは言及していません。

環境

  • macOS: 10.15.2
  • terminal: iTerm

  • Project概要

    • 言語: Nuxt.js, TypeScript
    • パッケージマネージャ: yarn

Docker の初期設定

Mac の Docker Desktop をインストール

  1. 以下からDockerをインストールします。

参考: https://hub.docker.com/editions/community/docker-ce-desktop-mac/

  1. インストール後、Docker.appをAppフォルダに移動
  2. clickするとアラートが出るためOKをclick
  3. sign inを求められるためsign in

ここでアカウントを持っていなければアカウントを作成します。

  • アカウント作成
    • アカウント名、PWD、メールアドレスを入力
    • 名前、職種、会社名等入力後、登録のメールアドレスに確認メールが来ます。
    • メールの指示通り対応して、完了

参考: https://docs.docker.com/docker-for-mac/install/

Dockerでbuildする

ubuntuをインストール

  • エラーが起こった環境の Ubuntu のversionを確認し、今回は 18.04.4 だったため、最新のものをインストールします。
    ターミナルで以下のコマンドを入力。
docker version       // dockerがインストールされているか確認
docker pull ubuntu   // ubuntuをインストール
docker images        // イメージ一覧を取得してubuntuがインストールされていることとバージョンを確認

docker run -it -d --name miiiii-ubuntu ubuntu     // ubuntuを起動
docker ps // 起動中のコンテナを確認

参考: https://www.sejuku.net/blog/82240

  • Ubuntu を起動する際名前をつけることができます。今回は miiiii-ubuntu としました。

必要なコマンドの確認

Dockerコンテナに入ります。

docker exec -it miiiii-ubuntu /bin/bash

コンテナ内に入ったため、以降は Ubuntu のコマンドで進みます。

cd /usr/src  // /usr/src に移動
mkdir app    // プロジェクトを置くためのディレクトリを作成
cd app       // 作成したディレクトリに移動

curlsudo をインストール

エラー解決のため、作業環境を整えていきます。
yarnをインストールするため、curlsudo をインストール。

  • sudo
find . -name sudo     // sudoコマンドが存在しないことを確認
apt-get update        // update
apt-get install sudo
  • curl
sudo apt install curl

参考: https://qiita.com/Sa2Knight/items/bdb6d821a3ac10088289

yarn をインストール

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

参考: https://classic.yarnpkg.com/en/docs/install#debian-stable

  • errorが出ました。
E: gnupg, gnupg2 and gnupg1 do not seem to be installed, but one of them is required for this operation
curl: (23) Failed writing body (577 != 1369)
  • 解決: エラー内容からパッケージがないということなので、 gnupg をインストール
apt-get install gnupg

再度 yarn をインストールしてエラーは出なかったため、以下のコマンドできちんとインストールされているか確認します。

yarn --version

error:

bash: yarn: command not found
  • まだ yarn がない。とのことなので sudo をつけて、別のコマンドで実行
sudo apt install yarn

バージョンが古いためyarnのアップグレードを行います。

sudo apt-get update 
sudo apt-get install yarn

yarn -v
1.21.1

今度は成功しました。

参考: https://phoenixnap.com/kb/how-to-install-yarn-ubuntu

Nuxtプロジェクトを作成

\usr\src\app に移動して以下のコマンドを実行

yarn create nuxt-app sample

error

error semver@7.1.3: The engine "node" is incompatible with this module. Expected version ">=10". Got "8.10.0"
error Found incompatible module.

nodeのバージョンが古い、とことなのでバージョンを確認

node --version             
v8.10.0

検証したいプロジェクトで使っているバージョン(10.16.0)に合わせます

sudo apt install nodejs npm
sudo npm install -g n

sudo n 10.16.0

一度 ubuntu から exit する

node -v
v10.16.0

再度プロジェクトを作成(yarn create nuxt-app sample)、成功しました。
あとは通常のNuxtのプロジェクトと同じようにComponentを作ったり等等、問題なく使えました。
今回の目的だった build も無事成功。

Epilogue

  • build できなかった理由は環境ではなく、依存関係にあるライブラリのバージョン問題でした。
    バージョンを最新にすると ubuntu 環境でも build は成功...。
    環境が問題なのか、という部分が今回のDocker立ち上げのキーポイントだったため、今回はここで一旦終了しました。
    なぜ環境によってインストールされるバージョンが異なるのか、は時間があれば確認します。

  • これまではVirtualBoxをよく使っていたので、初めてDockerを使ってみました。
    つまずいたところは特になく、基本公式のドキュメント通りに進めれば問題はないと感じました。
    ミニマムなトライ内容でしたが、初心者という壁は超えられたので、これからもっと慣れていこうと思います!

課題

  • 環境の違いでバージョンが異なってインストールされるのは何故なのか。わかり次第別の記事を書きます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NestJSアプリケーションのビルドサイズをncc使って300MB減らした話

Dockerイメージサイズをできるだけ小さくする際に試行錯誤した結果、nccを使ってイメージサイズを減らせたので備忘録

ncc使う前 ncc使った後 結果
599MB 245MB 354MB削減!

Image from Gyazo

ビルド手順

nccはTypeScriptをサポートしています。ですが、tsconfig.jsonの指定ができないためtsconfig.app.jsonのような複数の設定ファイルを保持している場合、うまく使用することができません。

そこで次の手順を踏みます。

例: apiというアプリをビルド
1. nest-cliでwebpackモードでビルドする: nest build api --webpack
2. 1の成果物をnccで更にビルドする ncc build dist/api.js -m -o dist/api

するとアプリに必要なファイルをまとめて出力してくれます。 Dockerイメージにはこれを含めればいいだけ。

Image from Gyazo

nccすごいですよ。webpackのやつを更にビルドできるの。

これにより、node_modulesが必要なくなり必要最低限のファイルのみがDockerイメージに含まれることになりました。
(node_modulesはもちろんnpm ci --productionでインストールしたもの)
Image from Gyazo

... attempted to require "@nestjs/microservices" but could not be resolved, assuming external.

(↑正確なエラー文忘れて記録にも残ってないので前半ぼかしてます...)

nccでビルドしたファイルを実行すると、@nestjs/microservices のインポートがうまく解決できないエラーが発生しました。関連issueはこちら: https://github.com/zeit/ncc/issues/463

私の場合、@nestjs/microservicesはメインで使っておらず@nestjs/terminusが動的に読み込みを行っているようです。terminusはヘルスチェックに必要ですが、少し前にサーバーレスに移行したため、重要度が低くなりました。なので@nestjs/terminus自体を削除しました。

nccの成果物にtypescriptが含まれる

場合によって、typescriptがまるっと含まれる可能性があります。47.8MB、めちゃくちゃでかい。当たり前なんですが、typescriptフォルダ自体削除しても特に動作に支障はありませんでした。
Image from Gyazo

え、300MBも削減されてんの?動くのこれ?という不安

Image from Gyazo

↑の結果を初めて見た時、かなり不安になりました。本当に最適化されただけ...?何か重要なファイル消えてない..?と言う感じで。
e2eテストをこのnccで行いましたが、ちゃんとテストは通っているので問題無しとしています(テスト書いててよかった)

あと、パッケージによっては古いバージョンのライブラリを参照してることがあります。バージョンの異なる同じパッケージが含まれているか調べましたが、ちゃんと含まれているようです(uuidのパッケージが4つも含まれてた...)。

更にpkgでシングルファイルにすれば完璧では...!?

alpine + pkg の組み合わせは動かなかった。static link周りでエラーが出る。
https://github.com/zeit/pkg-fetch/pull/72
そもそもpkgはサーバーレス用途では使わないでってREADMEに書いてあるし使うのは辞めた。
https://github.com/zeit/pkg/blob/master/README.md

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

備忘録集[Vue.js+Laravel+docker]

一つの記事に書く程ではないけれども、
ハマった所を今後同じ所でハマった同志のため、
また物忘れが最近酷いので再度自分がハマらないため
自分が躓いた所を備忘録集として残します。
基本的だけれども見落としやすい所が中心です。

備忘録なので書きなぐりの文章が多いです。
また間違い等があるかもしれないので、
都度修正していきます。

Javascript関連:VueJS,typescript,axios等

1.axiosのdeleteの方法

postとは異なる方法で設定する必要がある。

axios.delete('url',
             params: { foo: 'bar' }
             ).then(
             //以下省略
             );

2.[Vue.js]async,awaitでreturnの結果としてaxiosでgetしたデータを取得する。

下の例はupdateDate関数でaxiosを使っている。
このupdateDate関数は外部から呼び出され、this.Dataの値を更新している。
しかしthisを使用しているので、thisに依存している。
依存を解消するなら、axiosの結果をupdateDataの外で受け取るべき。
しかしaxiosはPromise型なので、thenの内部でreturnを書いても値を返さない。

改善前
methods:{
    updateData(url) {
      //データ取得
      axios
        .get(
          url
        )
        .then(response => {
          this.Data=response;
          //下のように書いてもresponseを返さない
          //return respose;
        })
        .catch(error => {
          console.log(error);
        })
    },
}

そこでasync,awaitを利用し以下のように書き直す。
then以降まで書かないでもaxios.get(url)までで,
結果を返してくれる。

参考:https://github.com/axios/axios

例1.thisをupdateDataの外部に出すことができた.
  mounted: async function() {
    let url = "どこかのurl";
    try {
      this.Data = await this.updateTable(url);
    } catch (err) {
      console.log(err);
    }
  },
  methods: {
    async updateData(url) {
      //axiosでデータ取得.get以降にthenを書かない。
      return axios.get(url);
    }
例2
    async function updateData2(url) {
        try {
          const response = await axios.get(url);
          return response;
        } catch (error) {
          console.error(error);
          return error;
        }
      }

注意:axiosをVue.jsのmounted内部で使っている。
Axiosは例外処理も含めて多用する可能性が高いので、
慣れてきたらaxios等の非同期処理を担うクラスを作成したほうがコードが散乱しないので良い。

3.tr等に普通にtransition-groupしてもアニメーションはつかない

参考:https://jp.vuejs.org/v2/guide/components.html#%E5%8B%95%E7%9A%84%E3%81%AA%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88

htmlの仕様によりliやtr等のタグはtableタグ直下等の特殊な条件でしか処理されない。
なので、tableとtrの間に普通にtransition-groupしてもtr以下が表示されなくなる。

失敗例
<tbody name="table-row">
<transition-group>
<tr v-for="data in showData" class="table-row-item" :key="data.id">  
<!--ここは表示されない.transition-groupをdiv等にしても同じ挙動になる.-->
</tr>
</transition-group>
</tbody>

対策の一例は、tbodyにis="transition-group"をつけること。

tbodyにisをつける回避策
<tbody name="table-row" is="transition-group">
<tr v-for="data in showData.data.data" class="table-row-item" :key="data.title">  

他の対策も複数あるので、必要な時は参考urlを参照。

4.アップロードされた画像ファイルのプレビュー表示方法 + URL.createObjectURLの仕様

画像の出力
    <div class="col-sm-1">
      <img class="icon-image border border-dark" :src="iconimg" />
    </div>

ファイルのアップロードを入力するhtmlタグは省略。
ファイルが入力された後、下のselectedFile関数を通して画像を格納する。

    selectedFile(event) {
      //必要に応じてkeyは変更
      this.iconfile = event.target.files[0];
      //プレビュー用のイメージ格納
      if (this.iconfile.type.startsWith("image/")) {
      //ObjectURLを生成
      this.iconimg = window.URL.createObjectURL(this.iconfile);
      }
    },

以下はjavascriptのcreateObjectURLの仕様の話。

createObjectURL(object)は、
与えられたobjectに対してアクセス可能となるURLを生成している。
このURLはクライアントのブラウザのメモリ上に保存されているblob(いわゆる生のデータ)を参照する。
アップロードされたファイルはクライアント上ではFileオブジェクトで保存されているが、
File自体がblobを継承しているため、createObjectURLでのURL生成が可能となる。
なので、createObjectURL関数の引数となるobjectはfile,blob,MediaSourceのどれかでなくてはならない。
生成されたブラウザを閉じるまでURLは有効。
ただ一度ブラウザに読み込まれればURLは必要ないので、可能ならば削除したほうが良い。
window.URL.revokeObjectURL(file);
でURLの削除が可能。

参考:
https://developer.mozilla.org/ja/docs/Web/API/File
https://qiita.com/azu369yu/items/8998e1e1536a5acfb7b3
https://qiita.com/iLLviA/items/c24f385ca3334c05a682

5.[typescript+Vue.js]子コンポーネントにて、propsを定義する際にはundefinedに注意

参考:https://qiita.com/kyokoshimizu/items/ee6c6e6b905b8aa101fa
参考https://tech-up.hatenablog.com/entry/2019/03/15/152258

前提:vue-property-decoratorをimportしている。

@Prop() public name:string;

のようにVue.jsのpropsをtypescriptで書くと

Property '----' has no initializer and is not definitely assigned in the constructor.

というエラーが出て怒られ、コンパイルができないケースがある。
しかし

@Prop() public name:string = "";

と初期化したらしたで、コンパイルも稼働はするが、コンソールには

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "propsValue"

とエラーが出てしまう。
この場合、前者はtypescriptのエラーで後者がVue.jsのエラーになる。

原因
typescriptの設定でstrictPropertyInitializationという設定がオンになっているためである。
strictPropertyInitializationは、「undefinedの許容されてない型を初期化させる」という設定になる。
要するに変数に初期値設定しろって設定。
最初に定義したPropsはstring型であるが、何も定義されていないのでundefinedが代入される。
string型にはundefinedが許容されていないため、strictPropertyInitializationによりエラーが発生した。
2回目のPropsのように初期化すればstrictPropertyInitializationによるエラーは解決しコンパイルは可能になるが、
これは子コンポーネントでpropsを書き換えているので、今後はVue.jsがエラーを発生させた。

対策
四苦八苦した過程が残るけど自分のお勧めは4番

1.tsconfig.jsonに以下を記述しstrictPropertyInitializationの設定をオフにする

strictPropertyInitialization:false

但し全体に影響する。

2.any型やstringならばUnion型に変更しundefinedで対応できるようにする。

    @Prop() public name:string|undefined;

ただし、number型の場合はundefinedまたはnullとunion型にできないので、
この解決はできない。

    @Prop() public name:any;

anyはどの型でも機能する。但しanyになるので型の意味があまりなくなる。
stringやnumberのような複雑じゃない型の時までanyにするのは悲しい。

3.そもそも@component以下に書く

@Component(
    {
        props:{
            placeholder:String,
        }
    }
)

但しexport以下で呼び出せなくなる。

4.型宣言の際に!をつける、または?をつける
参考:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#strict-class-initialization
参考:https://dev.classmethod.jp/server-side/typescript-assertions/

    @Prop() public name!:any;

!はコンパイラにこの型はnon-nullですよと伝える意味がある。
初期化されてないが実際には外部で変数が代入されている(丁度今回みたいな)場合に使える。
ちなみに @Prop() の中身にはoptionが設定できる。

ソースより
export interface PropOptions<T=any> {
  type?: PropType<T>;
  required?: boolean;
  default?: T | null | undefined | (() => T | null | undefined);
  validator?(value: T): boolean;
}

defaultとか設定したいときは次のような感じ

@Prop({default:"text"}) public type!:string;

ちなみに上のソースコードでも出現しているが、!の代わりに?をつけても解決する。
?は代入されてなくても構わない、という意味になる。

6.[Vue.js]vue-routerのto属性に対してparamを設定しpropを渡したい時、pathではなくnameでurlを呼び出さないといけない

<router-link
:to="{name:'hoge',params:{huga: 'hage'}}"
>

でないといけない。router.jsの方でnameで設定しないとparamsが有効にならない。
pathを設定するとurlに直接paramsを組み込まなければならない。

Laravel

1.モデルでSELECTする時にidを取得しないと、そのインスタンスにsaveもupdateもできない

大ハマり
参考:https://qiita.com/moimoinon/items/5adb4b179e3c25d189a2

悪い例
$data = Article::select('title','updated_at')->with('hashtags:name')->get();

例のようにモデルのidを取得していないインスタンスにsaveメソッドを使用して更新しようとした場合、
saveの結果としてtrueが返されてもデータベース上では更新されない。
この後の例等、予期せぬ挙動を生むことが多いので、selectする時は基本的にidは取得したほうが良い。

2.EagerLoadを使う場合、SELECTでidを取らないとwithで参照してくれない

参考:https://mseeeen.msen.jp/laravel-5-5-get-specified-column-with-with/

relationのwithも、idを軸にリレーション先のデータを取得している。
よって、もしSELECT元でidが選択されていない場合、withの参照先のデータも取得されない。

良い例
//もしidのカラムを取得していない場合はhashtagsが空になってしまう
$data = Article::select('title','updated_at','id')->with('hashtags:name')->get();

3.belongsToの場合のモデル名は単数。データ取得の際も関数でなくプロパティを通して取得。

HasManyと同じつもりで複数形にすると、参照先モデルの取得が正しくされない。

悪い例
    public function admins(){
        return $this->belongsTo(Admin::class);
    }

belongsToの参照先は1対多の1側なので、単数にしなければならない。

良い例
    public function admin(){
        return $this->belongsTo(Admin::class);
    }

リレーション先のデータを取得する際も単数形で指示する。
プロパティでアクセスできるのが大きな違い。

    //adminに対して()をつけずにプロパティでアクセスできる。
    public function scopeGetAdminName($query,$id){
        return $query->find($id)->admin->name;
    }

    //EagerLoad,withのadminが単数形になるのがhasManyの時との違い
    public function scopeWithAdmin($query){
        return $query->with('admin:id,name');
    }

その他

1,[docker] php:7.4.2-apacheのdockerイメージでドキュメントルートを変更する方法

/etc/apache2/sites-available/000-default.confのドキュメントルートを変更

000-default.conf
<VirtualHost *:80>
    # The ServerName directive sets the request scheme, hostname and port that
    # the server uses to identify itself. This is used when creating
    # redirection URLs. In the context of virtual hosts, the ServerName
    # specifies what hostname must appear in the request's Host: header to
    # match this virtual host. For the default virtual host (this file) this
    # value is not decisive as it is used as a last resort host regardless.
    # However, you must set it for any further virtual host explicitly.
    #ServerName www.example.com

    ServerAdmin webmaster@localhost
        #ここを変更
    DocumentRoot /var/www/html/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub Actionsでビルドするコンテナ内でGitHubのprivate repositoryをセキュアに参照する

はじめに

GitHub Actions、便利ですよね
ソースコードの変更後、いちいち手元でdocker buildしてpushなんてやってられないですし、
外部CIツールを新たに導入するよりは全部GitHub内で完結してたほうがシンプルです。

しかしながら別のprivate repositoryにある社内用ライブラリを持ってくるのが地味に面倒だったのでやり方を書きます

1行で

リポジトリsecretsにトークンを入れてBuild-time secretsでコンテナ内に注入

説明

認証方法

GitHub→GitHub内とは言え認証は必要です
httpsかsshで認証することになります
権限を細かく絞れるためトークンを介するhttps接続の方が良いと思います

https

下記記事のようにトークンを作成し、トークンを用いて認証します
この際、個人ユーザのトークンを利用するとアカウント削除時にトークンが使えなくなりそうなので、マシンユーザを作成してそちらでトークンを作成します。マシンユーザがcloneしたいリポジトリのread権限を持っている必要があります

Dockerfileのbuildで簡単にGithubのプライベートリポジトリをクローンする方法 - Qiita
https://qiita.com/Jah524/items/fa68f99c8b787f94b884

ssh

GitHubに登録してある公開鍵に対応する秘密鍵をコンテナ内に入れてしまえば接続はできます
ただユーザに許可されている全権限がついてしまうので、トークンを利用したほうがより安全ですね

Build-time secrets

リポジトリにトークンを直書きするのはもちろん、docker build--build-argに渡す方法も安全であるとは言えません
Build-time secretsという機能があるのでこちらを使いましょう

Docker Engine 18.09 から使える Build-time secrets を試してみた | はったりエンジニアの備忘録
https://blog.manabusakai.com/2018/12/docker-build-secret/

コンテナにsecretsを渡す

下記ドキュメントにrepo-tokenで渡すとあるので、そうすればいいのかと思ってしまいがちなのですが(1敗)、
この形で渡したトークンはActionsの中のcloneで使えるだけなので、コンテナに渡す場合は普通にenvを使います

GITHUB_TOKENでの認証 - GitHub ヘルプ
https://help.github.com/ja/actions/configuring-and-managing-workflows/authenticating-with-the-github_token

    steps:
    - uses: actions/labeler@v2
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}

コード

事前にリポジトリのsecretsにMACHINE_USER_TOKENの名前でトークンを入れておきます
下記のようにファイルの形でコンテナにトークンを渡します

github_actions_ecr.yml
      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          TOKEN: ${{ secrets.MACHINE_USER_TOKEN }}
        run: |
          echo $TOKEN >> .token
          DOCKER_BUILDKIT=1 docker build --secret id=token,src=.token \
            -t $ECR_REGISTRY/$ECR_REPOSITORY:latest \
            .
          rm .token
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest

Dockerfileの1行目にマジックコメントを入れます

# syntax = docker/dockerfile:1.0-experimental

Dockerfileでは下記のように受け取ります
pyproject.tomlにはssh形式でパスを入れておく想定で(どちらでもいいのですが手元で作業する分にはsshのほうが便利)
それを置換してトークンを入れています

COPY pyproject.toml .
RUN --mount=type=secret,id=token TOKEN=$(cat /run/secrets/token) \
  && sed -i "s/ssh:\/\/git@github.com/https:\/\/$TOKEN@github.com/g" pyproject.toml \
  && pip install . && rm pyproject.toml
pyproject.toml
[tool.poetry.dependencies]
<tool_name> = {git = "ssh://git@github.com/<org>/<repo>.git", tag = "1.0"}

GithubActionsのログにも秘匿化された状態で出力されています

#18 9.075 Collecting <tool_name>@ git+https://***@github.com/<略>

まとめ

Build-time secretsでクレデンシャルを安全に扱いましょう
https://docs.docker.com/develop/develop-images/build_enhancements/#new-docker-build-secret-information

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む