docker初试

357 阅读5分钟

docker可以将运行环境和代码打包成一个镜像,使用时直接运行镜像,可以免去不同机器部署时的麻烦。今天研究一下docker的基本使用。用docker打包一个node

node代码如下:

const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {
  ctx.body = 'Hello World';
});

app.listen(3333);

然后在根目录创建dockerfile, 如下:

FROM node
COPY . .
RUN npm install
EXPOSE 3333
CMD ["npx", "pm2", "-n", "main", "restart", "/src/index.js"]

我的步骤很简单,使用node镜像提供node环境,然后把当前目录的内容复制到docker的容器里面。我把容器理解为使用本地的linux内核的空目录。因此拷贝过来之后,容器里面的目录结构跟我项目里的一样,我项目目录结构如下:

node-test
├─dockerfile
├─package-lock.json
├─package.json
├─src
|  └index.js

node-test相当于容器根目录,那后续的话应该就是直接在容器根目录安装依赖。这里暴露出一个3333端口,因为listen就是3333端口,便于和外界端口做映射。最后跑npx pm2 -n main restart '/src/index.js'命令。

使用docker build -t node-test .命令打包,-t 用来命名打包出来的镜像名字,最后的.用来告知dockerfile的位置。命令运行后没有报错,然后我使用docker images查看,如下:

REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
node-test    latest    b0cd73088ae0   27 minutes ago   963MB
node         latest    1db64f55f800   3 days ago       936MB

node是我下载的镜像,node-test是刚刚打出来的。貌似离成功不远了?然后我运行docker run node-test,就报错了,提示/src/index.js不存在,看来是COPY那里出问题了。那我看看到底打了什么东西,改一下dockerfile,CMD改成 ['ls', '-al'],输出如下:

total 240
drwxr-xr-x   1 root root   4096 Jan 24 14:19 .
drwxr-xr-x   1 root root   4096 Jan 24 14:19 ..
-rwxr-xr-x   1 root root      0 Jan 24 14:19 .dockerenv
drwxr-xr-x   1 root root   4096 Jan 12 04:01 bin
drwxr-xr-x   2 root root   4096 Jul 10  2020 boot
drwxr-xr-x   5 root root    340 Jan 24 14:19 dev
-rw-r--r--   1 root root    129 Jan 24 14:18 dockerfile
drwxr-xr-x   1 root root   4096 Jan 24 14:19 etc
drwxr-xr-x   1 root root   4096 Jan 12 10:30 home
drwxr-xr-x   1 root root   4096 Jan 12 04:01 lib
drwxr-xr-x   2 root root   4096 Jan 11 00:00 lib64
drwxr-xr-x   2 root root   4096 Jan 11 00:00 media
drwxr-xr-x   2 root root   4096 Jan 11 00:00 mnt
drwxr-xr-x   1 root root   4096 Jan 24 14:19 node_modules
drwxr-xr-x   1 root root   4096 Jan 20 20:26 opt
-rw-r--r--   1 root root 154255 Jan 24 14:19 package-lock.json
-rw-r--r--   1 root root    290 Jan 24 14:19 package.json
dr-xr-xr-x 110 root root      0 Jan 24 14:19 proc
drwx------   1 root root   4096 Jan 24 14:19 root
drwxr-xr-x   3 root root   4096 Jan 11 00:00 run
drwxr-xr-x   1 root root   4096 Jan 12 04:00 sbin
drwxr-xr-x   2 root root   4096 Jan 24 13:45 src
drwxr-xr-x   2 root root   4096 Jan 11 00:00 srv
dr-xr-xr-x  13 root root      0 Jan 24 14:19 sys
drwxrwxrwt   1 root root   4096 Jan 20 20:26 tmp
drwxr-xr-x   1 root root   4096 Jan 11 00:00 usr
drwxr-xr-x   1 root root   4096 Jan 11 00:00 var

可以看到,docker还是加了一些很眼熟的文件夹,/var、/bin之类的。但是COPY指令的执行跟我想象的一致,项目的内容确实是直接拷贝到容器的根目录里面了(怪不得网上的例子都是新开一个目录,直接在根目录太乱了)。仔细一看,命令错了,pm2 应该用的start命令。重新来打包,然后运行docker run -p 8000:3333 node-test,这次成功了,输出了pm2的成功信息,然后访问浏览器的8000端口,无法访问。我使用docker ps查看在运行的docker进程,发现没有。也就是pm2挂掉了。百度了一下,大概就是说docker运行完CMD脚步之后就关掉了,就跟你打开一个终端,运行pm2,然后把终端关掉,pm2也就关掉了,度娘提供了几种办法,我唯一能看懂的就是在cmd后面加个tail -f命令,让他一直执行不完。于是我改成了这样:

FROM node
COPY . .
RUN npm install
EXPOSE 3333
CMD npx pm2 -n main start /src/index.js && npx pm2 logs main

运行成功,刷新浏览器8000端口,能看到hello world的正常输出。然后运行。

为了确认真的没有依赖本地的环境。我把本地npx改个名字,如下:

bin cd /usr/local/binbin ls               
2to3                          git                           kubectl.docker                python3-32
2to3-3.7                      git-credential-osxkeychain    node                          python3-config
MotionPro                     git-cvsserver                 notary                        python3.7
com.docker.cli                git-shell                     npm                           python3.7-32
docker                        gitk                          npx                           python3.7-config
docker-compose                hub-tool                      pip3                          python3.7m
docker-credential-desktop     hyperkit                      pip3.7                        python3.7m-config
docker-credential-ecr-login   idle3                         pydoc3                        pyvenv
docker-credential-osxkeychain idle3.7                       pydoc3.7                      pyvenv-3.7
easy_install-3.7              kubectl                       python3                       vpnkit
➜  bin npx -v
6.14.5bin mv npx npx2
➜  bin npx -v     
zsh: command not found: npx

然后stop容器,重新运行,依然正常!

正在运行的容器还可以进去,跟平常的终端一样。

➜  docker docker ps                        
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS          PORTS                    NAMES
9071e2fa8c20   node-test   "docker-entrypoint.s…"   39 seconds ago   Up 38 seconds   0.0.0.0:8000->3333/tcp   upbeat_chatelet
➜  docker docker exec -it 9071 sh          
# npx pm2 list
┌─────┬─────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id  │ name    │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├─────┼─────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0   │ main    │ default     │ N/A     │ fork    │ 44       │ 72s    │ 0    │ online    │ 0%       │ 40.8mb   │ root     │ disabled │
└─────┴─────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
# 

一套demo下来3小时,感觉还挺简单入手的样子,有空再多多研究