加快开发Node.js使用OpenShift

智能甄选 2018-01-30 10:49:11

在这篇博客里,我想介绍一个“不同”的工作方式与OpenShift,使用Node.js来创建一个Web应用程序使用OpenShift。

在这篇博客里,我想介绍一个“不同”的工作方式与OpenShift。在典型的方式来部署一个蚕茧OpenShift,我们有一套非常有用的对象;我们已建立/图像配置。这就隐藏了图像构建的细节,让我们感到痛苦,但有时我们只想看到云中运行的代码。或者,我们想看看我们的服务/应用程序是否能够与附近的服务交互,或者我们有一些代码,但我们还不想使用Git回购协议。为了解决这个问题,我将展示initcontainers的概念,以及如何通过创新点我们实现一些很酷的东西,像部署我们的代码里面运行的容器。

​入门

本指南是取决于你使用的OpenShift安装或您已经安装使用minishift或使用OC集群本地机器OpenShift。

一旦进入,登录。

我们的工作空间配置

一旦你有了OpenShift运行起来,你已经登录,下一步是创建一个项目:

oc new-project my-project

图像

我们需要得到节点。js配置了我们需要工作的工具。要导入它,我们需要一个ImageStream对象,它将抓取我们的图像,并使它可以访问我们的项目。

oc import-image cvr-node:latest --from=docker.io/cvaldezr/nodejs --confirm

这将会在mhart/阿尔卑斯图像中抓取这个映像,其中包括节点、NPM、no恶魔,以及所有必要的工具来构建本地插件。该图像仅为89MB,因此部署速度非常快。

模板

接下来,我们需要获取Pod的模板定义。稍后我会详细解释这个结构。

curl -o pod.yml https://gist.githubusercontent.com/cesarvr/2dedd0bb912be441aa98b67e1ac4bcc6/raw/2cf75a5512014fd40086375d5a46c81940c53fc8/pod.yml

获得该文件后,您需要修改第12行并为您的图像添加URL。你可以通过以下方式获取URL:

oc get is #<DOCKER REPO is the url we need to copy>

这就是模板的外观。你可以看到它很好很短:

apiVersion: v1

kind: Pod

metadata:

name: node-dev

labels:

app: node-js-dev

spec:

containers:

- name: nodejs

image: 172.30.1.1:5000/devel/cvr-node

command: ['/bin/sh', '-c']

args:

- cd /app/;

echo folder:$PWD;

npm install;

nodemon $(node -e "console.log(require('./package.json').main)")

volumeMounts:

- mountPath: /app

name: app-volume

- mountPath: /.npm

name: npm-cache

ports:

- containerPort: 8080

initContainers:    # This is the init container it will wait until app/ folder is in sync.

- name: folder

image: busybox

command: ['/bin/sh', '-c']

args: ['until [ "$(ls -A ./app/)" ]; do echo "waiting for user to push..."; sleep 2; done']

volumeMounts:

- mountPath: /app

name: app-volume

volumes:

- name: app-volume

emptyDir: {}

- name: npm-cache

emptyDir: {}

查看要点的代码。

接下来要做的是使用我们的模板创建我们的Pod。

oc create -f pod.yml

为了检查状态,我们可以使用这个命令。

oc get pods 

我们应该看到创建是成功的,如果不是,请确保模板有来自您的ImageStream的正确的图像URL,并且您有权限将它导入到您的项目中。

编写一些代码

现在是有趣的部分。让我们在Node.js中编写一个小的hello world服务器应用程序。

const express = require('express')

const app = express()

app.get('/', (req, res) => res.send('Hello World!!!'))

app.listen(8080, () => console.log('Example app listening on port 8080!'))

将此文件保存为app.js,请访问包。json,设置"主"属性。您将看到,模板配置正在寻找该属性来定位和执行应用程序的入口点。你可以改变并改进它以满足你的需要。

{

"name": "hello",

"version": "1.0.0",

"description": "",

"main": "app.js",

"scripts": {

"test": "echo \"Error: no test specified\"exit 1",

"start": "node app.js"

},

"author": "",

"license": "GPL",

"dependencies": {

"express": "^4.16.2"

}

}

使用npm安装express安装依赖项——保存,但只用于在我们的package.json中注册依赖项。

部署

首先,我们需要将文件发送到Pod,在我的例子中,它被命名为node-dev。你可以使用oc来检查你的名字。

oc rsync -c folder . node-dev:app/

打开我们的Pod。

oc expose pod node-dev --port=8080

oc expose service node-dev

现在访问您的新创建的服务。

oc get route -o wide

node-dev-devel.127.0.0.1.nip.io

修改

现在让我们来改变一些。

const express = require('express')

const app = express()

app.get('/', (req, res) => res.send('Hola Mundo!!!'))

app.listen(8080, () => console.log('Example app listening on port 8080!'))

修改完成后,转到控制台并写入:

oc rsync . node-dev:app/

现在在浏览器中刷新一下。

注意,在我们的例子中,我们没有使用-c文件夹,这是因为我们现在针对的是运行时容器(稍后我会详细解释这一点)。

刚才发生了什么?

为了解释所发生的事情,让我们快速查看一下模板。

apiVersion: v1

kind: Pod

metadata:

name: node-dev

labels:

app: node-js-dev

在这里,我们定义了pod的名称和标签,没有什么特别有趣的。

我们的node.js运行时容器

spec:

containers: 

- name: nodejs

image: 172.30.1.1:5000/devel/cvr-node

command: ['/bin/sh', '-c']

args:

- cd /app/;

echo folder:$PWD;

npm install;

nodemon $(node -e "console.log(require('./package.json').main)") 

volumeMounts:

- mountPath: /app

name: app-volume

- mountPath: /.npm

name: npm-cache

ports:

- containerPort: 8080

这是主控制舱。正如您所看到的,它使用的是我们前面导入的oc导入图像的图像。我还包括一些启动Pod命令sh -c,它将使用args运行一些shell命令。基本上,它会进入应用程序/文件夹运行npm安装并启动nodemon,但如果我们这样做并发布一个图像,它会立即崩溃,因为nodemon无法找到任何东西。如果我们有办法等待,直到我们的挂载点有一些文件,我们可以避免一个无限的崩溃循环。

使用InitContainer的解决方案

Pods对象有这个神奇的功能,叫做initcontainer,这意味着你可以有一个容器来为你做一些初始化工作。当您想要运行一个轻量级容器和一个装满编译工具的包(例如,如果您想要一个包含所有编译/构建工具的InitContainer,然后是一个运行时容器,只有一个非常简单的容器,只需要运行一些必需的工具)时,这将非常有用。

initContainers: # This is the init container will wait until app/ folder is in sync.

- name: folder

image: busybox

command: ['/bin/sh', '-c']

args: ['until [ "$(ls -A ./app/)" ]; do echo "waiting for user to push..."; sleep 2; done']

volumeMounts:

- mountPath: /app

name: app-volume

这就是我们的InitContainer的样子。我只选择一个很小的图像,Busybox,并运行一个小脚本,以阻止PodInit状态下的Pod执行。

如果您很好奇,您可以通过oc log -c文件夹node-dev -f来获取这个Pod的日志。您将看到“等待用户推动…”“每两秒钟,当你运行oc rsync -c文件夹时。nodedev:app/,您正在与InitContainer同步,并通过这样做,直到["$(ls -A ./app/)]”);不再是正确的,它将终止与InitContainer关联的sh命令。

结论

我在寻找使用Openshift/Kubernetes的创造性方法方面有很多乐趣,所以我希望您能找到有用的模板,您可以将它调整到您自己的用例中,或者更好地改进它。另外,我使用了Node。因为我在日常工作中使用了这种语言,但是我认为在Java中实现这一点没有任何问题。如果运行时容器只是一个等待EAR的JVM,在某个目录中WAR(可能我有点过时),然后在每次文件系统发生变化时都进行热部署,这将非常酷。

另外,我想补充的是,这种方法不是水平规模友好的,或者基本上您需要将代码推进到每个Pod,因为在这个示例中,我只是使用了容器的文件系统。您可以通过将文件系统设置为PVC(持久的容量索赔)来克服这种限制,然后将它与您的容器共享,有一些挑战,但我认为它可以工作,但这是另一篇文章。

了解更多关于init容器的信息。

无论你是新到容器还是有经验,下载这个小抄可以帮助你遇到你最近没有完成的任务。

0 阅读:0
智能甄选

智能甄选

技术交流、资源共享,是程序员的网上乐园。