费了点劲,总算是能在容器里运行这个Blogifier了。(补充:这边文章转载的原来博客的文章)
先记录一下最后使用的方式,然后附上碰到的问题和一些想法。
构造记录
构造文件环境
- 创建一个空目录作为docker的基础目录
- 进入到该目录,然后将博客项目克隆到其中,假定目录名称为Blogifier
构建docker镜像
在同一目录层级创建Dockerfile,Dockerfile文件内容如下:
```docker
# 首先使用构建镜像构建
FROM microsoft/dotnet:sdk AS build-env
WORKDIR /app
ARG appdir=Blogifier
# 拷贝所有程序文件到中间镜像中,恢复所需的库
COPY $appdir/ ./
RUN dotnet restore
# 发布生成镜像
RUN dotnet publish -c Release -o out
# 通过构建镜像生成运行镜像
FROM microsoft/dotnet:aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/src/App/out .
COPY --from=build-env /app/plugins/Common/out/ .
COPY --from=build-env /app/src/Upgrade/out/ .
ENTRYPOINT ["dotnet", "App.dll"]
```
这里有几个碰到的问题
- 如果不从
microsoft/dotnet:sdk
镜像构建,而是直接在机器上构建然后拷贝到docker镜像中,会找不到sqlite的库。怀疑是不同的环境依赖不同造成的 - 这个blogifier的目录结构相对复杂,拷贝时注意拷贝文件的目录结构。而且
Common.dll
这个库虽然依赖,但是发布缺没有拷贝进去,这应该是代码问题
执行如下命令构建docker镜像:
```shell
docker build -t myblog .
```
运行docker镜像
这里将log文件,数据库文件和data文件都挂在成了volumn,这样在容器外也能看到。
```shell
docker run -d -p 8000:80 --name myblog
--mount source=blogdb,target=/data
--mount source=blogdata,target=/app/wwwroot/data
--mount source=bloglog,target=/app/Logs
myblog
```
由于我的虚拟机开放了8000端口,所以也做了端口映射
问题记录
调试文件结构
一开始dotnet运行总是报错,而且提示不友好,怀疑是里面的文件不对,所以想打印docker镜像文件结构。
费了点功夫,发现两个方发
- 在dockerfile中,想要的地方,通过
RUN ls
指令打印 - 镜像已经构造好后,如果是ENTRYPOINT方式(我的dockerfile就是),可以通过
docker run --entrypoint ls myblog
这样的方式,修改image入口,执行ls
dockerfile运行目录
一开始以为dockerfile的copy命令能够拷贝host上的任意文件到image中,后来才了解到,只有当前目录(或者说PATH目录,实际上好像就是当前目录)里的内容,能被找到。
这是因为docker执行build命令时,会先将当前环境文件发送给docker的实际服务,其他目录的内容build服务是找不到的。
arg的用法
一开始我是想把外部编译好的文件,直接copy到image中(后来发现这样找不到库,还是要在微软的image里编译才行),想利用ARG传入拷贝的目录。结果每次都拷贝不到。
后来发现除了上面说的dockerfile的运行目录问题,还有个问题是ARG的作用域是从ARG定义的参数,到下一个FROM为止,不能跨越FROM。
所以每个FROM想要使用ARG,需要再声明一下ARG。
补充一个检查已经运行的docker镜像的方发
docker attach [container]
的确可以,但是对于我这种占用控制台的单进程情况,就什么页看不到,而且一不小心ctrl+c
,连container都杀死了
在SO上看到一个方发:
docker exec -t -i {container name } {command to exe}
这样就可以轻松执行ls等命令了