【Heroku】akhileshns/heroku-deploy@v3.12.12でRailsをデプロイするとerror:0308010C:digital envelope routines::unsupportedが発生する件について
どうもてぃ。
暖冬と言われていますが、一気にさむくなりましたね。体調には充分気をつけて残り少ない今年を乗り切りたいです。
今回は結構苦戦しました。
当方、Railsアプリケーション(not api mode)をGitHub Actionを用いてHerokuへ自動デプロイをしてます。が、先日突然nodejsのバージョン違いで発生するopensslのエラーがデプロイ時に出たので解決するに至りました。
現状出ている記事のどれを参考にしても解決できず、力技でなんとかしましたのでご参考に。
環境
エラーログ
remote: -----> Installing node-v20.9.0-linux-x64 remote: -----> Installing yarn-v1.22.19 remote: -----> Detecting rake tasks remote: -----> Preparing app for Rails asset pipeline remote: Running: rake assets:precompile remote: /tmp/build_0eb98de1/vendor/ruby-2.7.8/lib/ruby/2.7.0/net/protocol.rb:66: warning: already initialized constant Net::ProtocRetryError remote: /tmp/build_0eb98de1/vendor/bundle/ruby/2.7.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:68: warning: previous definition of ProtocRetryError was here remote: /tmp/build_0eb98de1/vendor/ruby-2.7.8/lib/ruby/2.7.0/net/protocol.rb:206: warning: already initialized constant Net::BufferedIO::BUFSIZE remote: /tmp/build_0eb98de1/vendor/bundle/ruby/2.7.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:214: warning: previous definition of BUFSIZE was here remote: /tmp/build_0eb98de1/vendor/ruby-2.7.8/lib/ruby/2.7.0/net/protocol.rb:503: warning: already initialized constant Net::NetPrivate::Socket remote: /tmp/build_0eb98de1/vendor/bundle/ruby/2.7.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:541: warning: previous definition of Socket was here remote: ** [NewRelic] FATAL : Config file at /tmp/build_0eb98de1/config/newrelic.yml doesn't include a 'staging' section! remote: D, [2023-11-05T22:31:32.095473 #308] DEBUG -- sentry: Initializing the background worker with 2 threads remote: D, [2023-11-05T22:31:32.095593 #308] DEBUG -- sentry: [Sessions] Sessions won't be captured without a valid release remote: RAILS_ENV=staging environment is not defined in config/webpacker.yml, falling back to production environment remote: yarn install v1.22.19 remote: [1/4] Resolving packages... remote: [2/4] Fetching packages... remote: [3/4] Linking dependencies... remote: warning " > @babel/plugin-proposal-private-methods@7.18.6" has unmet peer dependency "@babel/core@^7.0.0-0". remote: warning "@babel/plugin-proposal-private-methods > @babel/helper-create-class-features-plugin@7.22.15" has unmet peer dependency "@babel/core@^7.0.0". remote: warning "@babel/plugin-proposal-private-methods > @babel/helper-create-class-features-plugin > @babel/helper-replace-supers@7.22.20" has unmet peer dependency "@babel/core@^7.0.0". remote: warning " > @babel/plugin-proposal-private-property-in-object@7.21.11" has unmet peer dependency "@babel/core@^7.0.0-0". remote: warning "@babel/plugin-proposal-private-property-in-object > @babel/plugin-syntax-private-property-in-object@7.14.5" has unmet peer dependency "@babel/core@^7.0.0-0". remote: [4/4] Building fresh packages... remote: Done in 14.64s. remote: Compiling... remote: Compilation failed: remote: Error: error:0308010C:digital envelope routines::unsupported remote: at new Hash (node:internal/crypto/hash:68:19) remote: at Object.createHash (node:crypto:138:10) remote: at CompressionPlugin.taskGenerator (/tmp/build_0eb98de1/node_modules/compression-webpack-plugin/dist/index.js:163:38) remote: at taskGenerator.next (<anonymous>) remote: at /tmp/build_0eb98de1/node_modules/compression-webpack-plugin/dist/index.js:216:49 remote: at CompressionPlugin.runTasks (/tmp/build_0eb98de1/node_modules/compression-webpack-plugin/dist/index.js:236:9) remote: at /tmp/build_0eb98de1/node_modules/compression-webpack-plugin/dist/index.js:270:18 remote: at _next0 (eval at create (/tmp/build_0eb98de1/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:37:17) remote: at eval (eval at create (/tmp/build_0eb98de1/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:53:1) remote: at WebpackAssetsManifest.handleEmit (/tmp/build_0eb98de1/node_modules/webpack-assets-manifest/src/WebpackAssetsManifest.js:486:5) remote: at AsyncSeriesHook.eval [as callAsync] (eval at create (/tmp/build_0eb98de1/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:49:1) remote: at AsyncSeriesHook.lazyCompileHook (/tmp/build_0eb98de1/node_modules/tapable/lib/Hook.js:154:20) remote: at Compiler.emitAssets (/tmp/build_0eb98de1/node_modules/webpack/lib/Compiler.js:491:19) remote: at onCompiled (/tmp/build_0eb98de1/node_modules/webpack/lib/Compiler.js:278:9) remote: at /tmp/build_0eb98de1/node_modules/webpack/lib/Compiler.js:681:15 remote: at AsyncSeriesHook.eval [as callAsync] (eval at create (/tmp/build_0eb98de1/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1) remote: at AsyncSeriesHook.lazyCompileHook (/tmp/build_0eb98de1/node_modules/tapable/lib/Hook.js:154:20) remote: at /tmp/build_0eb98de1/node_modules/webpack/lib/Compiler.js:678:31 remote: at AsyncSeriesHook.eval [as callAsync] (eval at create (/tmp/build_0eb98de1/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1) remote: at AsyncSeriesHook.lazyCompileHook (/tmp/build_0eb98de1/node_modules/tapable/lib/Hook.js:154:20) remote: at /tmp/build_0eb98de1/node_modules/webpack/lib/Compilation.js:1423:35 remote: at AsyncSeriesHook.eval [as callAsync] (eval at create (/tmp/build_0eb98de1/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1) remote: at AsyncSeriesHook.lazyCompileHook (/tmp/build_0eb98de1/node_modules/tapable/lib/Hook.js:154:20) remote: at /tmp/build_0eb98de1/node_modules/webpack/lib/Compilation.js:1414:32 remote: at eval (eval at create (/tmp/build_0eb98de1/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:14:1) remote: at process.processTicksAndRejections (node:internal/process/task_queues:95:5) remote: remote: remote: ! remote: ! Precompiling assets failed. remote: ! remote: ! Push rejected, failed to compile Ruby app. remote: remote: ! Push failed remote: Verifying deploy...
解決方法
- GitHub Actionに
NODE_OPTIONS=--openssl-legacy-provider
を追加する - package.jsonでnode versionを固定する(engine指定)
↑2つの方法では解決できませんでした。今出てる解決方法はだいたいそれな気がする。
実際自分がやったのはHeroku側で NODE_OPTIONS=--openssl-legacy-provider
を設定することでした。
- 該当アプリケーション選択
- Settingsへ
- Config VarsでReveal Config Varsを押す
- NOTE_OPTIONS, --openssl-legacy-provider を追加
これがアプリケーションコードを修正せずHeroku側の設定のみで解決できる方法です。
デプロイ検証するために毎度コードの設定をいじってGitHub ActionsをReRunする必要はありませんでした。
おわりに
おわり。
【wordpress】contact form 7でinternal server errorが発生するときの対処法
お久しぶりです、もてぃです。
前回記事を書いてから半年以上が経過し、もうあと2ヶ月で今年も終わってしまいますね。時間の流れは残酷です。
今回はグループ会社のwordpressを新サーバーに移行した際に起きたエラーの解決方法を書いていきます。
新・旧サーバーについて
旧サーバー
諸事上によりphp, kusanagiを吹き飛ばしてしまったのでうる覚えです。
新サーバー
いずれもwebサーバーはapacheを使用しています(本当はnginxを使いたいが普段管理している人が使えないため)
contact form 7で起きたエラー
送信時に何も起きなかったので開発者コンソールを確認しました。それが以下。
さらに中を見てみる
全く意味不明。
なのでサーバーにsshしてログを確認します。
ログを確認する
centos stream 9のkusanagiで構築したサーバーの設定ファイルの場所は少し特殊です。
例えばapacheやphp-fpmの場所は /etc/opt/kusanagi
配下に作成されます(/etc
配下ではないです)。
ログも同じく変わった場所にあり、 /var/opt/kusanagi/log
配下にあります。今回対象のログは /var/opt/kusanagi/log/php-fpm/error.log
を見ればOK。
ログの中身が以下。
NOTICE: PHP message: PHP Warning: Attempt to read property "post_parent" on null in /home/kusanagi/hogehoge/DocumentRoot/wp/wp-content/plugins/code-snippets/php/snippet-ops.php(581) : eval()'d code on line 3 NOTICE: PHP message: PHP Fatal error: Uncaught TypeError: implode(): Argument #2 ($array) must be of type ?array, string given in /home/kusanagi/hogehoge/DocumentRoot/wp/wp-content/plugins/contact-form-7-to-database-extension/CF7DBPlugin.php:849 Stack trace: #0 /home/kusanagi/hogehoge/DocumentRoot/wp/wp-content/plugins/contact-form-7-to-database-extension/CF7DBPlugin.php(849): implode() #1 /home/kusanagi/hogehoge/DocumentRoot/wp/wp-content/plugins/contact-form-7-to-database-extension/CFDBIntegrationContactForm7.php(55): CF7DBPlugin->saveFormData() #2 /home/kusanagi/hogehoge/DocumentRoot/wp/wp-includes/class-wp-hook.php(309): CFDBIntegrationContactForm7->saveFormData() #3 /home/kusanagi/hogehoge/DocumentRoot/wp/wp-includes/class-wp-hook.php(331): WP_Hook->apply_filters() #4 /home/kusanagi/hogehoge/DocumentRoot/wp/wp-includes/plugin.php(522): WP_Hook->do_action() #5 /home/kusanagi/hogehoge/DocumentRoot/wp/wp-content/plugins/contact-form-7/includes/submission.php(616): do_...
CF7DBPlugin.php
の849行目を修正すればよさそう。でも可能ならプラグインの中身はさわりたくないなぁ…ということで検索。
同じ人いたけど、ちがうっぽい。
どうしたものか。。
php implode()の確認
そもそものエラー内容の implode()
関数がどういうふうに使われるか確認してみる。
リファレンス
implode(string $separator, array $array): string
Rubyでいう Array#join
みたいな挙動。
今の環境がphp8なので
implode(array $array, string $separator): string
の挙動が削除されているとのこと。
contact form 7 DBの該当箇所を修正する必要があるなこれ。
該当ファイル
843 foreach ($cf7->posted_data as $name => $value) { 844 $nameClean = stripslashes($name); 845 if ($this->fieldMatches($nameClean, $noSaveFields)) { 846 continue; // Don't save in DB 847 } 848 849 $value = is_array($value) ? implode($value, ', ') : $value; // ここ!!!! 850 $valueClean = stripslashes($value); 851 852 // Check if this is a file upload field 853 $didSaveFile = false; 854 if ($cf7->uploaded_files && isset($cf7->uploaded_files[$nameClean])) { 855 $foundUploadFiles[] = $nameClean; 856 $filePath = $cf7->uploaded_files[$nameClean]; 857 if ($filePath) { 858 $content = file_get_contents($filePath); 859 $didSaveFile = $wpdb->query($wpdb->prepare($parametrizedFileQuery, 860 $time, 861 $title, 862 $nameClean, 863 $valueClean, 864 $order++, 865 $content)); 866 if (!$didSaveFile) { 867 $this->getErrorLog()->log("CFDB Error: could not save uploaded file, field=$nameClean, file=$filePath"); 868 } 869 } 870 } 871 if (!$didSaveFile) { 872 $wpdb->query($wpdb->prepare($parametrizedQuery, 873 $time, 874 $title, 875 $nameClean, 876 $valueClean, 877 $order++)); 878 } 879 }
修正したのがこれ
$value = is_array($value) ? implode(', ', $value) : $value;
これでおk。
phpの再起動 & 送信確認
$ sudo systemctl restart php-fpm.service
うまくいきましたー。
結論
メンテできないなら使うな。
あと、アプデするならちゃんとプラグインも整理しましょうね!反省!
【Docker】alpine containerでless: unrecognized option: Xが発生するとき
どうもてぃ。
railsを僕の大好きなdockerで動かしていて、今回も素敵なエラーが発生したので対処法をここに記す。
発生したエラー内容
% docker compose run --rm web rails c [+] Running 2/0 ⠿ Container postgres Running 0.0s ⠿ Container redis Running 0.0s ruby/3.0.0 isn't supported by this pry-doc version Running via Spring preloader in process 29 Loading development environment (Rails 6.1.1) [1] pry(main)> Company.find(62).products Company Load (0.7ms) SELECT "companies".* FROM "companies" WHERE "companies"."id" = $1 LIMIT $2 [["id", 62], ["LIMIT", 1]] Product Load (0.8ms) SELECT "products".* FROM "products" WHERE "products"."company_id" = $1 [["company_id", 62]] less: unrecognized option: X BusyBox v1.32.1 () multi-call binary. Usage: less [-EFIMmNSRh~] [FILE]... View FILE (or stdin) one screenful at a time -E Quit once the end of a file is reached -F Quit if entire file fits on first screen -I Ignore case in all searches -M,-m Display status line with line numbers and percentage through the file -N Prefix line number to each line -S Truncate long lines -R Remove color escape codes in input -~ Suppress ~s displayed past EOF
デフォルトのalpine linuxにはless
コマンドは入ってないってことらしい。alpine imageが最小構成だから当たり前か。
解決方法
二点あります。
- Dockerfileのランタイムパッケージにlessを追加する
- apk add lessで追加する
alpine imageを利用しているのに、サーバー起動に不要なパッケージを入れるのは好ましくないので、ランタイムパッケージにlessを追加するのは却下。
apk add less
を立ち上げてるコンテナに直接叩きこむ方法でいきましょう。
# コンテナでコマンドを叩かずシェルを起動する(bashでもおk) $ docker compose run --rm web sh /myapp # apk add less . . . /myapp # rails c [1] pry(main)> Company.first.products # => 無事表示された
終わり
この記事を見たものに幸あれ。
今年の抱負、やりたいこと・目標
どうもてぃ。書くのが遅れてもう2月になっちゃいました。
去年はたしかtwitterで抱負をつぶやいて、結局何をやりたかったのか、やりたかったことの何を成し遂げられたのか、が全然わからなくなっていたので今回は記事にして、自分を逃げられないようにしたいと思います。
やりたいことがたくさんなので多方面で書いていきます。
仕事・エンジニアとして
今年の抱負
心身ともに自己管理に気を付けて、これまでよりも圧倒的に成長する
子供がうまれ今までよりも成長速度は遅くなってしまいましたが、ある程度諦めながら(どうしようもないので)できるときに全力を尽くして成長していこうと思います。
子供が生まれて4年目でやっと葛藤から抜け出せそうです。
やりたいこと・目標
- Elixirを業務レベル、サービス開発レベルまで極める
- PhonenixとAshを使っていろいろ作ってみる
- 応用情報の資格取る(4月)
- ブログを作って、はてなブログを卒業する
- Next.jsで作る予定
- 会社で定期的な勉強会を実施する
- 今年もちゃんと稼ぐ
- 会社でも個人でも必ず月締めをする(経費精算も)
家庭
今年の抱負
子供2人の思い出をいっぱい作る
去年末にたっかいカメラ買いました、娘(3歳)の幼稚園参観のために。
それだけじゃなく息子(1歳)も歩けるようになったし、食べるものの幅も広がってきているので、いろんなところに遊びに行ったり旅行に行ったりして、たっかいカメラで思い出を撮りまくりたいと思います。
やりたいこと・目標
- 旅行に行く
- 息子のためにアンパンマンミュージアムに行く
- 住宅ブログを定期的に書く(絶対)
- イヤイヤ期の娘にもっと優しくする
ギター
今年の抱負
少なくとも週1は絶対弾く、月1で何か曲を弾けるくらいに戻す
マジでギター弾いてない。大学時代あほみたいに没頭して楽しんでたのに…。
まずは弾く習慣をつけようかなと思います。ほんと曲が弾けなくなってるし、もしかしたら楽譜も読めなくなってるかもしれない。
最近はあまりゲームやってないので、その代わりにこっちに注力してみようかなと思います。
やりたいこと・目標
- 3か月に1回くらいのペースで曲をアップする
- 月1で曲を弾けるようにする
- ジブリ・FFの曲を弾きたい
- ギターを持ったらまず基礎練やる
筋トレ
今年の抱負
BP100kg、SQ140kg、DL140kgに頑張って戻す
筋トレもほとんど宅トレしかしてないです。去年数えるくらいしかジムに行っていない…。
ずっと家にいるので脚筋がめっちゃすくなくなってるのにも関わらず、過去最高の体重なため最高にデブってます。
これは今年全部筋肉に変換するしかない、とりあえず前の状態にもどす!とギターを頑張るのと同じ感じで頑張りたいと思います。。
ちゃんと痩せるだけじゃなく筋肉ガッツリつけます。
あと今年に入って頸椎ヘルニアになってしまったので、そこもリハビリで治しながら頑張っていきたいと思います。
やりたいこと・目標
ゲーム
今年の抱負
ほどほどにして優先順位を下げる
以前スマブラ中毒者だった自分は、休憩時間にスマブラ、仕事終わったらスマブラ、docker build時間にスマブラ、スマブラ、すまぶら、すまbあsbt24てゃjんd;lfv「会え4bが「’いb;あstば」gじゃ
マジでスマブラジャンキーで負けたらイライラするし、やっても面白くないのにやっちゃうし、なんなんでしょうねあのゲーム。
ただ、とある大会で辞めようと決心をし無事1回戦敗退で気持ちよくやめることができたので、あまりゲームをやらなくなりました。
しかーし!今年の4月にはロックマンエグゼアドバンスドコレクションが発売され、過去のロックマンエグゼ全シリーズが遊べるようになるのです。激熱。
ダークソウルも定期的にやりたくなるし、中途半端にやってるドラクエ7、クロノトリガー、ゼルダの伝説ゆめを見る島、メダロット2、モンスターハンター2ndGなどなど…やりたいゲームがたくさんで人生が終わりそう。
でも自分には上記に書いたように他にもやりたいことがたくさんあるので、なるべくゲームにはまらないよう優先度をさげて楽しもうと思います。
やりたいこと・目標
以上!
今年の抱負絶対こなしてみせます。
毎月末に振り返りをやり、毎回この記事を読み返してちゃんとやりたいことができてるか確認していこうと思います。
皆さんもぜひ書いてみてね。
おつぽよ。
【雑記】Nestjs/Prisma/GraphQLをPlanetScaleとFly.ioへデプロイできるリポジトリを作った
どうもてぃ。
作りました。興味がある人は気軽に触ってみてください。
当該リポジトリ
デプロイ手順
前提として pscale
コマンド、flyctl
コマンドが実行できるようにしておいてください。npm(yarn)が入ってないのは論外で。
PlanetScaleの作成
$ pscale auth login $ pscale database create nestjs-sample --region ap-northeast $ pscale branch create nestjs-sample dev $ pscale branch promote nestjs-sample main $ pscale password create nestjs-sample dev <name> # nameは識別子なのでなんでもおk
pscale password list
でも取得できますが、DATABASE_URL
の形式に書き換えるのだるいのでPlanetScaleのダッシュボードで確認してください。
データベース → connectで表示されます。
passwordがまだ作成できてない場合は New password
を押しましょう。DATABASE_URL
が出来上がったらコピーしておいてください。flyctl
で使用します。
Fly.ioの作成
$ flyctl auth login # databaseはPlanetScaleを使用するのでNo # Dockerfileを上書きしないように注意 # Dockerfileがあるため最後にデプロイするかどうか聞かれますがNoで(DATABASE_URLを設定してないため) # fly.tomlは上書きしてください $ flyctl launch # DATABASE_URLは上でコピーしたやつ # 後ろのパラメータ大事、絶対忘れるな $ flyctl secrets set DATABASE_URL="mysql://~~~~~~~~~~~~~~~~~~~~~~~~~/nestjs-sample?sslaccept=strict?sslcert=/etc/ssl/certs/ca-certificates.crt" $ flyctl deploy
特に問題なければデプロイできているでしょう、きっとね。
苦労したこと
WLS2環境で認証画面が立ち上がらない
最初 pscale
コマンドでPlanetScaleへschema.prismaを反映させようとしていました。
が、まず pscale auth login
ではまった。
chromeが立ち上がらない。ctrl + c
でキャンセルすると認証画面のURLが表示されるが、アクセスしても無効化されている(そりゃそうだ)。
wsl2だとやっぱりpscaleコマンドでchrome立ち上がらないっぽいな。issueあがっておりますがな。https://t.co/lHXDzIuUza
— もてぃ💪Engineer (@nil_motty93) 2023年1月29日
wsl2でpscaleコマンド使う場合はいったんsudoじゃないとうまくいかん。
— もてぃ💪Engineer (@nil_motty93) 2023年1月29日
あと、/root/.config/planetscaleディレクトリを作っておく必要があって、sudo pscale auth loginした後のアクセストークンがここに入る。
根本的にはまだ解決できていませんが、いったんsudoで実行し生成したアクセストークンを実行ユーザーのディレクトリに移動させることでうまくいきました。
wsl2環境ではpscale auth loginはスーパーユーザーで行い、生成されたアクセストークンを実行ユーザーのディレクトリに移動させる…という厄介なムーブが必要になることが判明したので、追記コメントした。https://t.co/lHXDzIuUza
— もてぃ💪Engineer (@nil_motty93) 2023年1月30日
解決したのでこのissueにコメントしときました。OSS活動じゃん。
根本解決は↓を今度ためしてみる予定。
ちなみに、pscale
コマンドだけでなくflyctl
コマンドでもCLI認証する必要があり、同じようにスーパーユーザーで実行し、アクセストークンを移動させるというムーブをしました。
くっそだる。
MacやLinux使ってる人は関係ないのでスルーでおkです。
Fly.ioでPrismaInitializationErrorが発生
Fly.ioにデプロイするタイミングでPlanetScaleにスキーマ構造を反映させているのですが、その際 PrismaInitializationError
が発生しデプロイに失敗していました。
長いですが以下
~/github.com/planetscale.nestjs-graphql-prisma main* % sudo flyctl deploy [sudo] password for motty: Update available 0.0.446 -> v0.0.451. Run "flyctl version update" to upgrade. ==> Verifying app config --> Verified app config ==> Building image Remote builder fly-builder-bitter-wave-2664 ready ==> Creating build context --> Creating build context done ==> Building image with Docker --> docker host: 20.10.12 linux x86_64 Sending build context to Docker daemon 191.9kB [+] Building 57.6s (18/18) FINISHED => [internal] load remote build context 0.0s => copy /context / 0.1s => [internal] load metadata for docker.io/library/debian:bullseye 2.0s => [stage-1 1/8] FROM docker.io/library/debian:bullseye@sha256:534da5794e770279c889daa891f46f5a530b0c5de8bfbc5e40394a0164d9fa87 0.0s => CACHED [builder 2/7] RUN apt-get update; apt install -y curl python-is-python3 pkg-config build-essential 0.0s => CACHED [builder 3/7] RUN curl https://get.volta.sh | bash 0.0s => CACHED [builder 4/7] RUN volta install node@18.8.0 yarn@1.22.19 0.0s => CACHED [builder 5/7] WORKDIR /app 0.0s => [builder 6/7] COPY . . 0.0s => [builder 7/7] RUN yarn install && yarn prisma generate && yarn build 49.7s => CACHED [stage-1 2/8] WORKDIR /app 0.0s => CACHED [stage-1 3/8] COPY --from=builder /root/.volta /root/.volta 0.0s => CACHED [stage-1 4/8] COPY --from=builder /app/node_modules ./node_modules/ 0.0s => [stage-1 5/8] COPY --from=builder /app/dist ./dist 0.1s => [stage-1 6/8] COPY --from=builder /app/.fly ./.fly 0.2s => [stage-1 7/8] COPY --from=builder /app/package.json ./ 0.1s => [stage-1 8/8] COPY --from=builder /app/yarn.lock ./ 0.0s => exporting to image 0.1s => => exporting layers 0.1s => => writing image sha256:393032d20e1b39441cedd0abc72eff5352edb0a377daedd8e0dabf6c293d7aa3 0.0s => => naming to registry.fly.io/nestjs-app:deployment-01GR1MYTD32RT3HDPMPYEGNK86 0.0s --> Building image done ==> Pushing image to fly The push refers to repository [registry.fly.io/nestjs-app] 1e854d6563d3: Pushed 1d6767cc453b: Pushed f7e90164f428: Pushed fbf3a65b1a93: Pushed 5d3c3bdc31ec: Layer already exists 5b1800ba7f88: Layer already exists 1b526d844305: Layer already exists a9099c3159f5: Layer already exists deployment-01GR1MYTD32RT3HDPMPYEGNK86: digest: sha256:0e210bfe9ec945b3e5c9cd95571ca559e3db8eaa140cba21b0fdec2cba066698 size: 1996 --> Pushing image done image: registry.fly.io/nestjs-app:deployment-01GR1MYTD32RT3HDPMPYEGNK86 image size: 847 MB ==> Creating release --> release v3 created --> You can detach the terminal anytime without stopping the deployment ==> Monitoring deployment Logs: https://fly.io/apps/nestjs-app/monitoring 1 desired, 1 placed, 0 healthy, 1 unhealthy [restarts: 2] [health checks: 1 total, 1 critical] Failed Instances Failure #1 Instance ID PROCESS VERSION REGION DESIRED STATUS HEALTH CHECKS RESTARTS CREATED cca60ea1 app 3 nrt run failed 1 total, 1 critical 2 46s ago Recent Events TIMESTAMP TYPE MESSAGE 2023-01-30T15:34:25Z Received Task received by client 2023-01-30T15:34:25Z Task Setup Building Task Directory 2023-01-30T15:34:51Z Started Task started by client 2023-01-30T15:34:57Z Terminated Exit Code: 1 2023-01-30T15:34:57Z Restarting Task restarting in 1.14956903s 2023-01-30T15:35:04Z Started Task started by client 2023-01-30T15:35:10Z Terminated Exit Code: 1 2023-01-30T15:35:10Z Restarting Task restarting in 1.058345s 2023-01-30T15:35:17Z Started Task started by client 2023-01-30T15:35:23Z Terminated Exit Code: 1 2023-01-30T15:35:23Z Not Restarting Exceeded allowed attempts 2 in interval 5m0s and mode is "fail" 2023-01-30T15:35:23Z Alloc Unhealthy Unhealthy because of failed task 2023-01-30T15:35:20Z [info][Nest] 659 - 01/30/2023, 3:35:20 PM LOG [InstanceLoader] ConfigHostModule dependencies initialized +1ms 2023-01-30T15:35:20Z [info][Nest] 659 - 01/30/2023, 3:35:20 PM LOG [InstanceLoader] AppModule dependencies initialized +0ms 2023-01-30T15:35:20Z [info][Nest] 659 - 01/30/2023, 3:35:20 PM LOG [InstanceLoader] PostsModule dependencies initialized +1ms 2023-01-30T15:35:20Z [info][Nest] 659 - 01/30/2023, 3:35:20 PM LOG [InstanceLoader] ConfigModule dependencies initialized +1ms 2023-01-30T15:35:20Z [info][Nest] 659 - 01/30/2023, 3:35:20 PM LOG [InstanceLoader] AuthorsModule dependencies initialized +0ms 2023-01-30T15:35:20Z [info][Nest] 659 - 01/30/2023, 3:35:20 PM LOG [InstanceLoader] GraphQLSchemaBuilderModule dependencies initialized +0ms 2023-01-30T15:35:20Z [info][Nest] 659 - 01/30/2023, 3:35:20 PM LOG [InstanceLoader] GraphQLModule dependencies initialized +1ms 2023-01-30T15:35:21Z [info][Nest] 659 - 01/30/2023, 3:35:21 PM LOG [RoutesResolver] AppController {/}: +199ms 2023-01-30T15:35:21Z [info][Nest] 659 - 01/30/2023, 3:35:21 PM LOG [RouterExplorer] Mapped {/, GET} route +4ms 2023-01-30T15:35:21Z [info]prisma:info Starting a mysql pool with 3 connections. 2023-01-30T15:35:21Z [info][Nest] 659 - 01/30/2023, 3:35:21 PM LOG [PrismaService] info: Starting a mysql pool with 3 connections. 2023-01-30T15:35:21Z [info]/app/node_modules/@prisma/client/runtime/index.js:24780 2023-01-30T15:35:21Z [info] throw new PrismaClientInitializationError(error2.message, this.config.clientVersion, error2.error_code); 2023-01-30T15:35:21Z [info] ^ 2023-01-30T15:35:21Z [info]PrismaClientInitializationError: Error opening a TLS connection: error:16000069:STORE routines:func(0):unregistered scheme:../deps/openssl/openssl/crypto/store/store_register.c:237:scheme=file, error:80000002:system library:func(0):reason(2):../deps/openssl/openssl/providers/implementations/storemgmt/file_store.c:267:calling stat(/etc/ssl/certs), error:16000069:STORE routines:func(0):unregistered scheme:../deps/openssl/openssl/crypto/store/store_register.c:237:scheme=file, error:80000002:system library:func(0):reason(2):../deps/openssl/openssl/providers/implementations/storemgmt/file_store.c:267:calling stat(/etc/ssl/certs), error:16000069:STORE routines:func(0):unregistered scheme:../deps/openssl/openssl/crypto/store/store_register.c:237:scheme=file, error:80000002:system library:func(0):reason(2):../deps/openssl/openssl/providers/implementations/storemgmt/file_store.c:267:calling stat(/etc/ssl/certs), error:16000069:STORE routines:func(0):unregistered scheme:../deps/openssl/openssl/crypto/store/store_register.c:237:scheme=file, error:80000002:system library:func(0):reason(2):../deps/openssl/openssl/providers/implementations/storemgmt/file_store.c:267:calling stat(/etc/ssl/certs), error:0A000086:SSL routines:func(0):certificate verify failed:../deps/openssl/openssl/ssl/statem/statem_clnt.c:1896: (unable to get local issuer certificate) 2023-01-30T15:35:21Z [info] at startFn (/app/node_modules/@prisma/client/runtime/index.js:24780:17) 2023-01-30T15:35:21Z [info] at async Proxy.onModuleInit (/app/dist/src/prisma/prisma.service.js:40:9) 2023-01-30T15:35:21Z [info] at async Promise.all (index 0) 2023-01-30T15:35:21Z [info] at async callModuleInitHook (/app/node_modules/@nestjs/core/hooks/on-module-init.hook.js:43:5) 2023-01-30T15:35:21Z [info] at async NestApplication.callInitHook (/app/node_modules/@nestjs/core/nest-application-context.js:178:13) 2023-01-30T15:35:21Z [info] at async NestApplication.init (/app/node_modules/@nestjs/core/nest-application.js:96:9) 2023-01-30T15:35:21Z [info] at async NestApplication.listen (/app/node_modules/@nestjs/core/nest-application.js:158:33) 2023-01-30T15:35:21Z [info] at async bootstrap (/app/dist/src/main.js:11:5) { 2023-01-30T15:35:21Z [info] clientVersion: '4.9.0', 2023-01-30T15:35:21Z [info] errorCode: 'P1011' 2023-01-30T15:35:21Z [info]} 2023-01-30T15:35:21Z [info]Node.js v18.8.0 2023-01-30T15:35:21Z [info]error Command failed with exit code 1. 2023-01-30T15:35:21Z [info]info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. 2023-01-30T15:35:21Z [info]Starting clean up. --> v3 failed - Failed due to unhealthy allocations - no stable job version to auto revert to and deploying as v4 --> Troubleshooting guide at https://fly.io/docs/getting-started/troubleshooting/ Error abort
Dockerfileに関しては flyctl launch
した際に生成されるDockerfileで少しばかりカスタマイズしています。
似た問題のIssueを見つけました。
sslcert pathを設定しないといけない…と。しかもそれがPrisma公式に書いてあった。
PlanetScaleにもdebianだったらこれ設定しろよって書いてました。
そしてflyctl launchして生成されるDockerfileのdebian:bullseye
imageには、なんと/etc/ssl
ディレクトリがなかった。証明書が存在しなかったのです…。
これはコンテナを立てて確認済みです。
正しくはbuilder imageではcurlをいれてるので証明書ca-certificates.crt
はあるのですが、実行image には存在してませんでした。
そのため、実行imageの方にCOPYしてあげる必要があった…と(apt installする手もありますが、実行imageが肥大化するので無し)。
FROM debian:bullseye as builder ARG NODE_VERSION=18.8.0 ARG YARN_VERSION=1.22.19 ENV NODE_ENV development ENV VOLTA_HOME /root/.volta ENV PATH /root/.volta/bin:$PATH RUN apt update && \ apt install -y curl python-is-python3 pkg-config build-essential apt-transport-https RUN curl https://get.volta.sh | bash RUN volta install node@${NODE_VERSION} yarn@${YARN_VERSION} WORKDIR /app COPY . . RUN yarn install && \ yarn prisma generate && \ yarn build FROM debian:bullseye ENV NODE_ENV production ENV PATH /root/.volta/bin:$PATH LABEL fly_launch_runtime="nodejs" WORKDIR /app COPY --from=builder /root/.volta /root/.volta COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist COPY --from=builder /app/.fly ./.fly COPY --from=builder /app/package.json ./ COPY --from=builder /app/yarn.lock ./ COPY --from=builder /etc/ssl /etc # これが必要!!!!!! CMD ["sh", ".fly/start.sh"]
あとDATABASE_URLにパラメータを設定したものをsecretsに反映させます。
$ flyctl secrets set DATABASE_URL='mysql://~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/nestjs-sample?sslaccept=strict?sslcert=/etc/ssl/certs/ca-certificates.crt'
これで無事認証も通り flyctl deploy
でPrisma schemaをPlanetScaleへ反映させることができました。
おめでとう。
おわり
私はいつも会社で新規プロジェクトが始まると、新しい技術を取り入れようとし一瞬で作れるリポジトリ作成マンになります。
自分にとっても会社にとっても他のエンジニア様たちにとってもメリットしかないので今後も続けていきてぇっすね。
ぜひぜひ使ってみてね。
これであなたもモダンなインフラを扱えるようになりますよぉ。
次はRenderかRailwayでデプロイする記事書こうかな。
【Selenium】location_once_scrolled_into_viewでelement not interactableが発生したときの対処方法
どうもてぃ。
自社開発でseleniumをよく使うのですが、とあるサイトをクローリングしているときに出くわしたエラーを力技で解決したので備忘録として残します。
環境
- wsl2
- ruby 3.1.2p20
- Google Chrome 109.0.5414.74 (wslへinstallしたもの)
コード
require 'selenium-webdriver' options = Selenium::WebDriver::Chrome::Options.new client = Selenium::WebDriver::Remote::Http::Default.new wait = Selenium::WebDriver::Wait.new(timeout: 20) options.add_argument('--headless') options.add_argument('--disable-gpu') options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') options.add_argument('--window-size=1920,1080') options.add_argument('--lang=ja-JP') driver = Selenium::WebDriver.for(:chrome, capabilities: [options], http_client: client) driver.get('https://example.com') footer = driver.find_element(:tag_name, 'footer') footer.location_once_scrolled_into_view
エラー内容
element not interactable (Session info: chrome=109.0.5414.74) #0 0x555fe9d48303 <unknown>: element not interactable (Selenium::WebDriver::Error::ElementNotInteractableError) (Session info: chrome=109.0.5414.74) from #1 0x555fe9b1cbbd <unknown> from #2 0x555fe9b530bc <unknown> from #3 0x555fe9b52669 <unknown> from #4 0x555fe9b79982 <unknown> from #5 0x555fe9b4e22f <unknown> from #6 0x555fe9b79b4e <unknown> from #7 0x555fe9b9188c <unknown> from #8 0x555fe9b79753 <unknown> from #9 0x555fe9b4ca14 <unknown> from #10 0x555fe9b4db7e <unknown> from #11 0x555fe9d9732e <unknown> from #12 0x555fe9d9ac0e <unknown> from #13 0x555fe9d7d610 <unknown> from #14 0x555fe9d9bc23 <unknown> from #15 0x555fe9d6f545 <unknown> from #16 0x555fe9dbc6a8 <unknown> from #17 0x555fe9dbc836 <unknown> from #18 0x555fe9dd7d13 <unknown> from #19 0x7f3bf207e609 start_thread from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/response.rb:56:in `assert_ok' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/response.rb:35:in `initialize' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/http/common.rb:83:in `new' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/http/common.rb:83:in `create_response' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/http/default.rb:103:in `request' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/http/common.rb:59:in `call' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/bridge.rb:625:in `execute' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/bridge.rb:411:in `send_keys_to_element' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/remote/bridge.rb:493:in `element_location_once_scrolled_into_view' from /home/motty/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/selenium-webdriver-4.7.1/lib/selenium/webdriver/common/element.rb:307:in `location_once_scrolled_into_view' from scraping.rb:49:in `block (2 levels) in <main>' from scraping.rb:36:in `each' from scraping.rb:36:in `block in <main>' from scraping.rb:24:in `each' from scraping.rb:24:in `<main>'
よくわからん…
動的な要素だからとか??
力技を実行
jsの力を発動します。
seleniumでjsを実行する場合はexecute_script
を使用します。
require 'selenium-webdriver' options = Selenium::WebDriver::Chrome::Options.new client = Selenium::WebDriver::Remote::Http::Default.new wait = Selenium::WebDriver::Wait.new(timeout: 20) options.add_argument('--headless') options.add_argument('--disable-gpu') options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') options.add_argument('--window-size=1920,1080') options.add_argument('--lang=ja-JP') driver = Selenium::WebDriver.for(:chrome, capabilities: [options], http_client: client) driver.get('https://example.com') footer = driver.find_element(:tag_name, 'footer') driver.execute_script("window.scrollTo(#{footer.location.x}, #{footer.location.y});")
要素の座標はdriver.find_element
して取得した要素に対して、location
にアクセスしてあげればx座標とy座標が入ってるので、この子たちを使ってあげましょう。
終わり
実際のコードは画像をfind_elementしていて、headless modeで起動せずに目視でちゃんと要素が表示されているにも関わらず、タイトルのようなエラーが出ていました。
解決策を探しているうちにissueも上がっていた気がしますが、なんかcloseされてたので今回は力技でひとまず解決。
同じエラーが発生したときの正攻法(?)として誰かの力になればばばば。
おつでした。
【Elixir】docker compose構成のelixirとpostgresqlが接続できなかった話
あけましておめでとうございますもてぃ。
今年一発目の記事はElixirです。
僕はdockerが大好きで愛してやまないので、Elixir * PostgreSQL構成のdockerリポジトリを作りました。
その際はまった内容を備忘録として残しておきたいと思います。
環境
- wsl2 windows ubuntu
- elixir 1.14.2-slim image
- postgresql 14.1-alpine image
docker-compose.ymlの構成
こんな感じ。
version: '3' services: postgres: build: ./postgres image: ecto-database container_name: ecto-database environment: POSTGRES_HOST_AUTH_METHOD: 'trust' TZ: 'Asia/Tokyo' volumes: - ./postgres/init:/docker-entrypoint-initdb.d - ecto-data:/var/lib/postgresql/data ports: - '5555:5432' restart: always app: build: . image: ecto-app container_name: ecto-app volumes: - .:/app tty: true stdin_open: true restart: always depends_on: - postgres volumes: ecto-data: driver: local
ライブラリにはecto
とpostgrex
を使用してます。
ecto.create
app containerに対してmix ecto.create
を実行しています。
# docker exec -it ecto-app mix ecto.createでもおk % docker compose exec app mix ecto.create Compiling 3 files (.ex) Generated ecto_app app 05:34:55.399 [error] GenServer #PID<0.284.0> terminating ** (DBConnection.ConnectionError) tcp connect (postgres:5555): connection refused - :econnrefused (db_connection 2.4.3) lib/db_connection/connection.ex:100: DBConnection.Connection.connect/2 (connection 1.1.0) lib/connection.ex:622: Connection.enter_connect/5 (stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 Last message: nil State: Postgrex.Protocol 05:34:55.407 [error] GenServer #PID<0.290.0> terminating ** (DBConnection.ConnectionError) tcp connect (postgres:5555): connection refused - :econnrefused (db_connection 2.4.3) lib/db_connection/connection.ex:100: DBConnection.Connection.connect/2 (connection 1.1.0) lib/connection.ex:622: Connection.enter_connect/5 (stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3 Last message: nil State: Postgrex.Protocol ** (Mix) The database for EctoApp.Repo couldn't be created: killed
いろいろ調べてみたら「postgresqlサーバーが立ち上がってない」だのいろいろ書かれてましたが、docker compose upで立ち上げたpostgresql コンテナは問題なく立ち上がってました。
docker-compose.ymlでentripointも設定して権限もしっかり付与しているので、ecto_appユーザーが接続できてないってこともないです。
念のため確認
% docker compose exec postgres psql -U ecto_app psql (14.1) Type "help" for help. ecto_app=# \du List of roles Role name | Attributes | Member of -----------+------------------------------------------------------------+----------- ecto_app | Superuser, Create role, Create DB | {} postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} ecto_app=#
ちゃんと権限もありましたね。
configの見直し
接続設定はconfig/config.exs
に書かれてます。
import Config config :ecto_app, EctoApp.Repo, database: "ecto_app", username: "ecto_app", password: "ecto_app_psql", hostname: "localhost", port: "5555" config :ecto_app, ecto_repos: [EctoApp.Repo] if Mix.env() == :dev do config :mix_test_watch, tasks: [ "credo" ] end
もともとpostgresqlをローカルにいれていない自分は、DBが必要になったときに毎回postgresql用のdocker-compose.ymlを作っていて、そのtemplateを毎度使っていました。
その設定をそのまま上のconfig.exsに反映していたのがまずかったのです…。
解決策
docker-composeで立ち上げる際のポート、ホストはdocker network上で生成されるものにおき替える必要があります。
docker-composeをみるとdatabaseのホストはpostgres
、ポートはdocker network上では5432
を開放しています。なのでその通りにconfig.exs
を変更してあげる。
import Config config :ecto_app, EctoApp.Repo, database: "ecto_app", username: "ecto_app", password: "ecto_app_psql", hostname: "postgres", port: "5432" config :ecto_app, ecto_repos: [EctoApp.Repo] if Mix.env() == :dev do config :mix_test_watch, tasks: [ "credo" ] end
再度ecto.createしてみると…
% docker compose exec app mix ecto.create Compiling 3 files (.ex) Generated ecto_app app The database for EctoApp.Repo has already been created
なんかすでに作られてましたが、うまくコマンド実行できました。
終わり
postgresqlとelixirの簡単なdocker compose構成が出来上がりました。
これでphoenixにも応用できるはずなので、phoenix tutorialをやる際はちょっとこのリポジトリをいじって圧倒的環境構築したいとおもいます。
Elixir/Phoenix極めるぞー!
(今年の抱負はまた別の記事で)