Bcrypt.Base.gensalt_nif/3 is undefined (Elixir)


表と裏、両面のこころがけ、どれもおろそかにしてはならじ。

Advent Calendar 2022 28日目1の記事です。
I'm ready for 12/25,2022
I'm looking forward to 12/25,2022
I can't wait for 12/25,2022
私のAdvent Calendar 2022 一覧


はじめに

Elixirを楽しんでいますか

Bcrypt.Base.gensalt_nif/3 is undefined

** (UndefinedFunctionError) function Bcrypt.Base.gensalt_nif/3 is undefined (module Bcrypt.Base is not available)

このエラーで悩んだことがありました。
一応解決できたので記事を残しておきます。

Bcrypt.Base.gensalt_nif/3 is undefined

けっこう悩んでいるfolksがいるようです。

私の場合

もともとローカルでPhoenixアプリを動かしました。
あとからDockerで動かそうとして、問題に遭遇しました。
結論をざっくりお伝えすると、ローカルマシン上で以前ビルドしたdeps_buildを見に行ってしまっていておかしな具合になっていました。

Dockerfiledocker-compose.ymlの書き方次第で解決できたのかもしれません。

私の場合は、まあ一回まっさらからやってみるかということで、Dockerのコンテナ、イメージ、ボリュームを消して、さらに_builddepsを消して、再度ビルドして動かしてみると動くようになりました。

だいたい以下のような感じです。

$ docker ps -a

でてきたCONTAINER IDIMAGEをメモ

$ docker rm <コンテナID>
$ docker rmi <Image名>
$ docker image prune
$ docker volume prune
$ rm -rf _build
$ rm -rf deps
$ docker-compose build
$ docker-compose up

Docker

あとから、Phoenixアプリに追加したDocker関係のファイルを説明します。

Configuration

使用する際には、config配下のファイルを少しデフォルトから変更する必要があります。

config/dev.exs
 config :realworld, Realworld.Repo,
   username: "postgres",
   password: "postgres",
-  hostname: "localhost",
+  hostname: "db",
   database: "realworld_dev",
   show_sensitive_data_on_connection_error: true,
   pool_size: 10

 config :realworld, RealworldWeb.Endpoint,
   # Binding to loopback ipv4 address prevents access from other machines.
   # Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
-  http: [ip: {127, 0, 0, 1}, port: 4000],
+  http: [ip: {0, 0, 0, 0}, port: 4000],
   check_origin: false,
   code_reloader: true,
   debug_errors: true,

Change to ip: {0, 0, 0, 0} to allow access from other machines.

このhttp: [ip: {0, 0, 0, 0}, port: 4000]設定を知らずに、あれ〜 http://localhost:4000 につながんないなあ〜 とけっこう悩んだりしました。

config/test.exs
 config :realworld, Realworld.Repo,
   username: "postgres",
   password: "postgres",
-  hostname: "localhost",
+  hostname: "db",
   database: "realworld_test#{System.get_env("MIX_TEST_PARTITION")}",
   pool: Ecto.Adapters.SQL.Sandbox,
   pool_size: 10

Docker関係のファイル

あとから、Phoenixアプリに追加したDocker関係のファイルは以下のようなものです。

Dockerfile
FROM hexpm/elixir:1.13.1-erlang-24.2.1-debian-bullseye-20210902-slim

RUN apt-get update && \
    apt-get install --yes build-essential inotify-tools postgresql-client && \
    apt-get clean

RUN mix local.hex --force && \
  mix archive.install hex phx_new --force && \
  mix local.rebar --force

ADD . /app
WORKDIR /app
EXPOSE 4000

CMD ["/app/entrypoint.sh"]

Dockerfileの内容はもうちょっと厳選できるのかもしれません。
bcryptのビルドにmakeが必要だというログがでていたので、エイってな具合でbuild-essentialを入れています。

docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - '4000:4000'
    volumes:
      - .:/app
    depends_on:
      - db

  db:
    image: postgres:13-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - 5432:5432
    volumes:
      - db:/var/lib/postgresql/data
volumes:
  db:
entrypoint.sh
#!/bin/bash
# Docker entrypoint script.

# Wait until Postgres is ready
echo "Testing if Postgres is accepting connections."
while ! pg_isready -q -h db -p 5432 -U postgres
do
  echo "$(date) - waiting for database to start"
  sleep 2
done

mix setup
mix deps.compile

exec mix phx.server
.dockerignore
deps
_build

Run

$ docker-compose build
$ docker-compose up

Visit: http://localhost:4000

テスト

$ docker-compose run --rm web mix test

Wrapping up

Enjoy Elixir
$\huge{Enjoy\ Elixir🚀}$

悩み多い記事でした。
一応動いたよ〜 くらいのものでして、まだまだ悩み多い記事です。
ただ、あれ〜 なんでDockerだと動かね〜んだー と次になったときにはヒントになりそうです。
ということを書いておかないと記憶に定着しないので、外化しておきます。
お付き合いありがとうございます


2022年に流行る技術予想 ーー それは、ElixirPhoenix LiveViewLivebookNerves Livebookです

Elixirの誕生日は、2012年5月24日です。
そのため、今年の2022年5月24日は10周年を迎えます。

iex> Date.diff(~D[2022-05-24], ~D[2022-01-27])
117

そうそう!
2月24日発売予定のWEB+DB PRESSで、ElixirPhoenixの特集がでますよ〜


I organize autoracex.
And I belong to NervesJP, fukuoka.ex, EDI.
I hope someday you'll join us.

We Are The Alchemists, my friends!