docker_utility_container_0">[docker] utility container
utility container 我感觉就是工具,可以减少一些系统安装软件的容器
使用场景
主要还是系统减负,比如说正常情况下运行一个 node 项目,那么系统上一定需要安装一个 npm,哪怕是创建一个新的项目,使用 npm init
,也是需要保证本机上安装一个 npm,但是如果将其放到 docker 容器中,那么就不需要安装 npm 了
如果只是 node,那么问题倒也不是很大,但是参考一下 laravel 项目,官方文说,必须 安装 PHP 和 Composer,推荐 安装 Node 和 NPM:
Before creating your first Laravel project, make sure that your local machine has PHP and Composer installed. If you are developing on macOS, PHP and Composer can be installed in minutes via Laravel Herd. In addition, we recommend installing Node and NPM
Installation
这种情况下,安装工具就相对而言比较困难
另一个情况是不同的库,但是会产生冲突。比如说 MariaDB 和 MySQL,默认导出的 port 都是 3306,但是二者不兼容,包括使用的 SQL Driver 都不一样。我就因为想要同时安装 MariaDB 和 MySQL 导致一些文件冲突,然后折腾了一个下午才彻底删除干净,重新安装了 MySQL
再后来干脆就使用 MySQL 的 docker 了
使用 util container 的方法
简单介绍一下用 util container 的方式
直接 -it
这种大多数情况下是需要用 REPL,如:
❯ docker run -it --rm node
11Welcome to Node.js v21.7.3.
Type ".help" for more information.
> 1 + 1
2
> console.log('hello docker')
hello docker
undefined
>
另一种使用方式如下:
❯ docker run -it node npm init -y
Wrote to /package.json:{"name": "","version": "1.0.0","description": "","main": "index.js","directories": {"lib": "lib"},"scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"
}
这样就可以创建一个空白的 node 项目了
另外也可以在 run 的同时 attach 一个 bash,这样可以直接通过命令行执行
exec
但是有的情况下,已经使用 docker run
,又想额外加一些功能,这时候就可以使用 exec
,如:
# 假设之前的指令是启动一个 node 容器
❯ docker exec -it sweet_nightingale npm init -y
Wrote to /package.json:{"name": "","version": "1.0.0","description": "","main": "index.js","directories": {"lib": "lib"},"scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"
}
exec
是在 docker 容器内运行指令的 arg,如果想要 attach bash 的话,那么容器就一定要在运行的状态才行
bind mounts util container
之前在 [docker] 数据的持久化 - Volume & bind mounts 提到可以把 docker 容器中的路径和本机的路径进行挂载,这样双向都能够被更新
这个思路也可以应用到 util container 上,这样就可以在本机修改代码,然后在 container 中即时更新。或者容器中修改了一些内容,本机上也获取同步更新
下面就实现一个 node 的 util container 的 bind mounts:
# 使用 slim 或者 alpine 会比完整的版本小很多
❯ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
node-util latest d006cdcdfc7d 7 seconds ago 132MB
node latest b6d2a1484e51 About an hour ago 1.1GB
# 然后进行 bind mount
❯ docker run -it -v "$(pwd):/app" node-util npm init -y
Wrote to /app/package.json:{"name": "app","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"
}
可以看到本机上也出现了对应的 package.json 文件
使用 Dockerfile
这里多提一下 ENTRYPOINT
,这是一个添加了之后 docker 永远会多执行的一个指令:
docker">FROM node:20-slimWORKDIR /appENTRYPOINT [ "npm" ]
这样就可以不用反复输入 npm
,因为每次执行的时候,npm
都会执行:
❯ docker run -it -v "$(pwd):/app" node-util init -y
Wrote to /app/package.json:{"name": "app","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"
}# 下载 node_module,注意这里是启动了一个新的 container
❯ docker run -it -v "$(pwd):/app" node-util installup to date, audited 1 package in 300msfound 0 vulnerabilities# 安装 express,注意这里启动了第三个 container
❯ docker run -it -v "$(pwd):/app" node-util install expressadded 64 packages, and audited 65 packages in 4s12 packages are looking for fundingrun `npm fund` for detailsfound 0 vulnerabilities
npm notice
npm notice New patch version of npm available! 10.5.0 -> 10.5.2
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.5.2
npm notice Run npm install -g npm@10.5.2 to update!
npm notice
完成之后,node_modules 也会被同步到本机上:
docker_compose_192">使用 docker compose
想要继续简化步骤,则是可以使用 docker compose:
version: "3.8"
services:npm:build: ./stdin_open: truetty: truevolumes:- ./:/app
这样可以少打一些字:
# can use --rm to remove the container after executing the command
❯ docker compose run npm init -y
WARN[0000] /Users/luhan/study/docker/section07/docker-compose.yaml: `version` is obsolete
[+] Creating 1/0✔ Network section07_default Created 0.0s
[+] Building 0.6s (6/6) FINISHED docker:desktop-linux=> [npm internal] load build definition from Dockerfile 0.0s=> => transferring dockerfile: 90B 0.0s=> [npm internal] load metadata for docker.io/library/node:20-slim 0.5s=> [npm internal] load .dockerignore 0.0s=> => transferring context: 2B 0.0s=> [npm 1/2] FROM docker.io/library/node:20-slim@sha256:7c5c3f250db850d159c5f5554a3a608a72eb721dd15451d294e3fe74f944a4fc 0.0s=> CACHED [npm 2/2] WORKDIR /app 0.0s=> [npm] exporting to image 0.0s=> => exporting layers 0.0s=> => writing image sha256:2d02c95f22951c1aea74c6c4d1cf6703115cbacbfeaccec867d55993b17894d3 0.0s=> => naming to docker.io/library/section07-npm 0.0s
Wrote to /app/package.json:{"name": "app","version": "1.0.0","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","dependencies": {"express": "^4.19.2"},"devDependencies": {},"description": ""
}
保持 node 项目运行
这个是只针对 node 的优化:
❯ docker run -d node:20-alpine tail -f /dev/null
Unable to find image 'node:20-alpine' locally
20-alpine: Pulling from library/node
4abcf2066143: Already exists
3bce96456554: Already exists
2bde47b9f7c3: Already exists
db3e2f2b6054: Already exists
Digest: sha256:7a91aa397f2e2dfbfcdad2e2d72599f374e0b0172be1d86eeb73f1d33f36a4b2
Status: Downloaded newer image for node:20-alpine
1ab1731f8bdc929e6274ebc4f3e7b95596a5d0d33be1b41c4eb2726ab3c8f1ae
❯ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1ab1731f8bdc node:20-alpine "docker-entrypoint.s…" 3 seconds ago Up 2 seconds sleepy_wright# 使用 exec 执行 sh
❯ docker exec -it sleepy_wright sh
/ # echo "bash is not present"
bash is not present
这样就可以进入到容器内执行命令,而不是反复重新起一个新的容器
⚠️:alpine 模式下 bash 不存在,所以可以使用 sh