【问题标题】:Integrating oracledb in cloudfoundry custom buildpack在 cloudfoundry 自定义 buildpack 中集成 oracledb
【发布时间】:2018-02-16 05:19:54
【问题描述】:

我们的目标是将我们的 node.js 网络服务集成到 cloudfoundry 中。由于我们需要 oracledb 模块来访问我们的数据库,因此我们不得不创建一个自定义 buildpack(从 cloudfoundry/nodejs-buildpack 分叉),它会安装所需的 oracle 即时客户端。

s.Stager.BuildDir() + '/instantclient-basic' 目录中下载并解压缩instantclient 和sdk 后,似乎我们必须将LD_LIBRARY_PATH 变量设置为这个路径。

因此,在/src/nodejs/supply/supply.go 文件中,我们添加了以下代码行:

if err := s.Stager.WriteEnvFile("LD_LIBRARY_PATH", filepath.Join(s.Stager.BuildDir(), "instantclient-basic")); err != nil {
    return err
}

但是,在安装此 buildpack 时的日志输出中,它列出了其他变量,如 NODE_ENVNODE_HOME(设置方式完全相同)我的变量 LD_LIBRARY_PATH 丢失。如何正确导出新的环境变量?

---- 编辑以回应 Daniel Mikusa 的回答 ---

我尝试遵循.profile 包括即时客户端文件方法:

- controllers
- public
- instantclient
| --- libclntsh.so
| ... 
app.js
server.js
package.json
.profile

.profile 文件如下所示:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/app/instantclient

不过,当我从中创建一个 .zip 并在我们的 cloundfoundry 上暂存一个新的 nodejs buildpack 时,我得到了与以前相同的错误:

ERR 错误:NJS-045:无法为 Node.js 6.11.2(linux,64)加载 oracledb 附加二进制文件

ERR Node.js require() 错误是:

ERR DPI-1047:无法加载 64 位 Oracle 客户端库:“libclntsh.so:无法打开共享对象文件:没有这样的文件或目录”。

你发现这里有什么错误吗?

【问题讨论】:

  • 如果这是一个 Linux VM 并且唯一的 Oracle 软件是 Instant Client,那么请按照 Instant Client 安装说明中的说明使用 ldconfig:oracle.com/technetwork/topics/… 这样可以避免必须在每个 shell 中设置 LD_LIBRARY_PATH正在调用 Node.js。
  • 我尝试写入文件/etc/ld.so.conf.d/oracle-instantclient.conf,但是,访问被拒绝,sudo 似乎也不可能。

标签: cloud-foundry


【解决方案1】:

我将首先在此处引用 buildpack 合同文档。

https://docs.cloudfoundry.org/buildpacks/custom.html#contract

您正在调用s.Stager.WriteEnvFile,您可以在此处查看源代码。

https://github.com/cloudfoundry/libbuildpack/blob/e915de2390c8dcc4f3a05dd747c7635454335e26/stager.go#L76

此方法正在编写一个 env 文件。来自 buildpack 文档...

可以在 /tmp/deps/IDX/ 内部创建以下目录,为后续构建包提供依赖项:

...

  • /env:包含用于暂存的环境变量,加载为 FILENAME=FILECONTENTS

因此,您添加的内容应该会创建一个 env 文件,以便后续构建包可以使用。那是你的意图吗?

如果您想在运行时(即您的应用程序运行时)设置环境变量,那么您需要修改 buildpack 的这一部分。

https://github.com/cloudfoundry/nodejs-buildpack/blob/master/src/nodejs/supply/supply.go#L586-L593

    scriptContents := `export NODE_HOME=%s
export NODE_ENV=${NODE_ENV:-production}
export MEMORY_AVAILABLE=$(echo $VCAP_APPLICATION | jq '.limits.mem')
export WEB_MEMORY=${WEB_MEMORY:-512}
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-1}
export LD_LIBRARY_PATH=/path/to/instant-client
`

    return s.Stager.WriteProfileD("node.sh", fmt.Sprintf(scriptContents, filepath.Join("$DEPS_DIR", s.Stager.DepsIdx(), "node")))

只需确保 /path/to/instant-client 在运行时容器中相关,而不是在暂存容器中。路径可能不同。


对于它的价值,如果你有很多需要这种调整的应用程序,我只建议分叉 buildpack。它需要维护以使 buildpack 保持最新状态,并且您不希望您的 fork 落后,否则您可能会在运行旧版本的 node 或 buildpack 提供的任何二进制文件时陷入困境,这可能存在安全漏洞。

如果您只有几个应用程序,您应该能够将即时客户端与您的应用程序文件捆绑在一起。为此,只需将即时客户端解压缩到项目文件夹的子文件夹中。然后将名为.profile 的文件添加到项目文件夹的根目录。在该文件中,添加LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/app/instant-client-folder

当您推送您的应用程序时,.profile 文件将被获取。这会将即时客户端文件夹附加到 LD_LIBRARY_PATH 环境变量中,这应该可以让您的应用程序使用它。

更多关于.profile的细节在这里 -> https://docs.cloudfoundry.org/devguide/deploy-apps/deploy-app.html#profile

【讨论】:

  • 非常感谢您提供的信息丰富的回答!由于我们基本上只有一个需要 oracledb 库的 node.js 应用程序,因此您的第二种方法听起来很有趣!看来我还是做错了什么,我已经更新了我的初始帖子。你发现有什么错误吗?
  • "因为 .profile 脚本在 buildpack 之后执行" --> 那么设置变量是不是太晚了,因为安装 node-oracledb 需要它已经设置?
  • @user66875 在暂存期间,oracle 库/NPM 试图对这些库做什么? .profile 只是一个运行时挂钩,因此在 buildpack 运行时不会应用它。您可以通过在本地出售您的依赖项来解决这个问题。见这里->docs.cloudfoundry.org/buildpacks/node/index.html#vendoring.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多