Dockerコンテナ内のディレクトリ構成を確認してみる
SBJソリューション部のserinaです。
先日、Dockerを用いた作業をしていてうまくいかないことがあり、立ち上がったコンテナの中身についてあまり理解してないなぁ、と感じたことがありました。
なので、今回は、Dockerコンテナのディレクトリ構成を確認してみます。
node.jsのアプリケーションを作成して確認してみる
ブラウザで Hello World!
を表示する簡単なnode.jsのアプリケーションを作成して、ディレクトリ構成を確認していきます。
ディレクトリ構成
~/tmp/myapp 19s
❯ tree .
.
├── Dockerfile
├── app.js
└── package.json
前準備: ファイル作成
Dockerfile
# ベースイメージを指定
FROM node:alpine
# 作業ディレクトリを設定
WORKDIR /app
# package.jsonとpackage-lock.jsonをコピー
COPY package*.json ./
# 依存関係をインストール
RUN npm install
# アプリケーションのソースコードをコピー
COPY . .
# アプリケーションを起動
CMD ["node", "app.js"]
app.js
// app.js
const http = require('http');
const hostname = '0.0.0.0';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
package.json
{
"name": "myapp",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"http": "0.0.0"
}
}
確認作業
Dockerをビルドします。
~/tmp/myapp 11s
❯ docker build -t myapp .
[+] Building 3.5s (10/10) FINISHED docker:rancher-desktop
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 393B 0.0s
=> [internal] load metadata for docker.io/library/node:alpine 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/5] FROM docker.io/library/node:alpine 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 980B 0.0s
=> [2/5] WORKDIR /app 0.0s
=> [3/5] COPY package*.json ./ 0.0s
=> [4/5] RUN npm install 3.4s
=> [5/5] COPY . . 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:34aec6d03e817ca9a7a3037683d519482717db47e9fec671f6103d1aa99ca05c 0.0s
=> => naming to docker.io/library/myapp
tree構造で確かめたいので、docker run
でコンテナのシェルに入ったら tree
コマンドを入れます。
❯ docker run -it myapp /bin/sh
/app # apk add --no-cache tree
fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/aarch64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/aarch64/APKINDEX.tar.gz
(1/1) Installing tree (2.1.1-r0)
Executing busybox-1.36.1-r29.trigger
OK: 12 MiB in 17 packages
全部表示すると大量に出てきてしまうので、1階層のディレクトリを確認してみます。
/app # tree -d -L 1 /
/
├── app
├── bin
├── dev
├── etc
├── home
├── lib
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin
├── srv
├── sys
├── tmp
├── usr
└── var
19 directories
Dockerコンテナ内ではLinuxベースのファイルシステムが使われています。
なので、それと似たようなディレクトリ構成になっています。
WORKDIR /app
したので、 /app
が作られていることが確認できます。
このディレクトリ配下を確認すると、ファイルがあることが確認できます。
/app # cd /app
/app # tree .
.
├── Dockerfile
├── app.js
├── node_modules
├── package-lock.json
└── package.json
node_modules
を確認してみる
グローバルインストールした場合の 先日、この問題で悩んだことがあり、package.jsonを作成しなかった場合は NODE_PATH
を通す場所があることがわかりました。
調べた結果、/usr/local/lib
にnode_modules
が作られることがわかっているので、そのことを確認していきます。
前準備: ファイルを変更
package.json
を削除します。
変更後のDockerfile
# ベースイメージを指定
FROM node:alpine
# 作業ディレクトリを設定
WORKDIR /app
# 環境変数を設定 <- 🌟追加
ENV NODE_PATH=/usr/local/lib/node_modules
# 必要なモジュールをグローバルにインストール <- 🌟変更
RUN npm install -g http
# アプリケーションのソースコードをコピー
COPY . .
# アプリケーションを起動
CMD ["node", "app.js"]
変更後のディレクトリ構成
~/tmp/myapp 57s
❯ tree .
.
├── Dockerfile
└── app.js
1 directory, 2 files
確認作業
再度、ビルドします。
❯ docker build -t myapp .
[+] Building 1.2s (9/9) FINISHED docker:rancher-desktop
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 428B 0.0s
=> [internal] load metadata for docker.io/library/node:alpine 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/4] FROM docker.io/library/node:alpine 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 454B 0.0s
=> CACHED [2/4] WORKDIR /app 0.0s
=> [3/4] RUN npm install -g http 1.1s
=> [4/4] COPY . . 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:052f11f8a331fc31cdb444f8772f29523941f18ba12a610358c816ae1cf4a5f3 0.0s
=> => naming to docker.io/library/myapp
treeコマンドをインストールします。
❯ docker run -it myapp /bin/sh
/app # apk add --no-cache tree
fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/main/aarch64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/community/aarch64/APKINDEX.tar.gz
(1/1) Installing tree (2.1.1-r0)
Executing busybox-1.36.1-r29.trigger
OK: 12 MiB in 17 packages
2階層までの usr/local
を確認します。
/ # tree -a -L 2 /usr/local
/usr/local
├── bin
│ ├── corepack -> ../lib/node_modules/corepack/dist/corepack.js
│ ├── docker-entrypoint.sh
│ ├── node
│ ├── npm -> ../lib/node_modules/npm/bin/npm-cli.js
│ ├── npx -> ../lib/node_modules/npm/bin/npx-cli.js
│ ├── yarn -> /opt/yarn-v1.22.22/bin/yarn
│ └── yarnpkg -> /opt/yarn-v1.22.22/bin/yarnpkg
├── include
│ └── node
├── lib
│ └── node_modules
└── share
├── doc
└── man
lib/node_modules
を見つけられました。
最後に
Dockerをふわっとした理解で使っていたので、もやもやがスッキリしました!