Dockerのruby:2.7-alpineでruby2.7がないといわれてしまう

# はじめに

これまでいくつかのDockerimageを構築してきました。OpenAPIとSinatraの組み合わせは、お手軽なのですが、これまで作成してきたイメージを作り直したところ問題が発生しました。

Dockerでbundle exec rackup ...を実行したタイミングでエラーメッセージが表示されてしまうようになりました。

```bash:エラーメッセージ
$ sudo docker run -it --rm  \
        --env LC_CTYPE=ja_JP.UTF-8 \
        --env RACK_ENV="deployment" \
        -p 8080:8080 \
        --name webapp mywebapp \
...
+ bundle exec rackup --host 0.0.0.0 --port 8080
env: can't execute 'ruby2.7': No such file or directory
```

コンテナ内のファイルを確認して、最後のメッセージは ./lib/ruby/2.7.0/bin/rackupコマンドがruby2.7を呼び出しているからということは分かりました。

Dockerfileは次のようになっていて、multi-stage buildを利用しています。


```dockerfile:Dockerfileの抜粋
FROM ruby:2.7-alpine as rubydev

RUN apk update && \
        apk add --no-cache tzdata bash ca-certificates make gcc libc-dev

COPY . /app
WORKDIR /app
RUN bundle config path lib
RUN bundle install

FROM ruby:2.7-alpine

RUN apk update && \
        apk add --no-cache tzdata bash ca-certificates

COPY --from=rubydev /app /app
WORKDIR /app

ADD run.sh /run.sh
RUN chmod +x /run.sh

RUN addgroup sinatra
RUN adduser -S -G sinatra sinatra
USER sinatra
RUN bundle config path lib ## generating the ~/.bundle/config file.

ENTRYPOINT ["/run.sh"]
```

# 理由

rackupを探してみると、2箇所に存在していて、なぜか lib/ruby/2.7.0/bin/rackup では ruby2.7バイナリを探していました。

```
+ find lib/ -name rackup
lib/ruby/2.7.0/bin/rackup
lib/ruby/2.7.0/gems/rack-2.2.3/bin/rackup
+ cat lib/ruby/2.7.0/bin/rackup
#!/usr/bin/env ruby2.7
...
+ cat lib/ruby/2.7.0/gems/rack-2.2.3/bin/rackup
#!/usr/bin/env ruby
...
```

ワークアラウンドで対応するのであれば、/usr/local/bin/ruby2.7 を準備する方法もあります。

```dockerfile:Dockefileに追加した1行
RUN ln -s ruby /usr/local/bin/ruby2.7
```

ただ、こういった現象が発生するはずがないと思っていたので、少し原因の調査を進めました。

# 原因

結論からいうと、問題は Dockerfile の次の箇所にありました。

```dockerfile:問題のあったDockerfileの抜粋
COPY . /app
```

ここではDockerfileを含めて全てのファイルをコピーしています。
Dockerfile自体は秘密ではないため、この方法自体は横着しているなという程度のものですが、問題はこの時点でカレントディレクトリの./lib/ruby/2.7.0/ ディレクトリもコピーされてしまったことでした。

コンテナを作成する前にコードをデバッグする目的で、ローカルのUbuntu環境でもrackupを起動しています。
そのため、bundle install コマンドを実行することで、./lib/ruby/2.7.0/bin/rackup が配置されていたのでした。

Ubuntuでは /usr/bin/ruby が ruby2.7へのシンボリックリンクとなっているため、このrackupはruby2.7から起動されるようになっていました。

```bash:Ubuntuに配置されたrackupコマンド
$ head -2 ./lib/ruby/2.7.0/bin/rackup
#!/usr/bin/env ruby2.7
#
```

他のDockerfileを処理するMakefileの中で、./lib/ruby ディレクトリを削除していたのですが、このイメージを作成する作業用リポジトリのMakefileには、このコードが含まれていませんでした。

```makefile:Makefileのdockerイメージをbuildする箇所の処理抜粋
## local debug用のコマンド
bundle-install:
        bundle install --path lib

## dockerイメージをbuild
docker-build:
        rm Gemfile.lock || true
        sudo docker build . --tag $(DOCKER_IMAGE)
```

Gemfile.lockファイル以外に、./lib/ruby/, ./.bundle/ ディレクトリを削除するコードを追加することで恒久的な対策となりました。

```makefile:必要な変更を加えた後のMakefileの例
NAME = sinatra-webapp
DOCKER_IMAGE = sinatra-webapp
DOCKER_IMAGE_VERSION = 0.1.1
IMAGE_NAME = $(DOCKER_IMAGE)
REGISTRY_SERVER = docker.io
REGISTRY_LIBRARY = please-overwrite-by-your-docker-id

docker-build:
        rm -f Gemfile.lock
        rm -fr lib/ruby
        rm -fr .bundle
        sudo docker build . --tag $(IMAGE_NAME)

docker-build-prod:
        rm -f Gemfile.lock
        rm -fr lib/ruby
        rm -fr .bundle
        sudo docker build . --tag $(IMAGE_NAME):$(DOCKER_IMAGE_VERSION) --no-cache

docker-tag:
        sudo docker tag  $(IMAGE_NAME):$(DOCKER_IMAGE_VERSION) $(REGISTRY_SERVER)/$(REGISTRY_LIBRARY)/$(IMAGE_NAME):$(DOCKER_IMAGE_VERSION)

docker-push:
        sudo docker push $(REGISTRY_SERVER)/$(REGISTRY_LIBRARY)/$(IMAGE_NAME):$(DOCKER_IMAGE_VERSION)
```

上記のMakefileはGitHubで公開している[docker-sccp-sinatra-sample](https://github.com/YasuhiroABE/docker-sccp-sinatra-sample)に含まれる _docker/Makefile からの抜粋です。

結果は勘違いから勝手に悩んでいるだけだったのですが、手持ちのコンテナをbuildするプロセスを再度チェックしました。他のイメージでは ./.bundle/ や、./lib/ruby を削除していたので、思い込みがあったこともあって、解決がすぐに出来ませんでした。

現在はテンプレートを準備しているので、基本的には同じような問題は発生していません。

以上