Commit 8bb13b47 authored by xuezj's avatar xuezj

nodejs

parent 0feedc49
const Koa = require('koa')
const Router = require('koa-router')
const error = require('../middleware/error')
const result = require('../middleware/result')
const namespaceRoute = require('./namespace')
const serviceRoute = require('./service')
function loadRoutes (router) {
router
.use(error())
.use(result())
.use('/namespace', namespaceRoute.routes())
.use('/service', serviceRoute.routes())
}
exports.start = function () {
// 加载各种服务
const app = new Koa();
const router = new Router();
// 加载所有路由
loadRoutes(router)
app.use(router.routes());
app.listen(4000);
console.log('app start', 4000)
}
\ No newline at end of file
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser');
const client = require('../services/tke.service').create({
secretId: 'AKID4rY7wwNphsUcaFsy1pRtKhQvDj4CA3Ac',
secretKey: 'YBduRnjgVRGzmagZJbss3Vo58wWCyhgc',
clusterId: 'cls-acfx4pvj',
region: 'ap-beijing'
})
const ReservedNamespace = ['default', 'kube-system']
const router = new Router();
module.exports = router
router.use(async (ctx, next) => {
// 默认使用腾讯云的服务
ctx.k8s = client
await next()
}, bodyParser())
// 查询namespace
router.get('/', async ctx => {
let data = await client.namespace_get()
ctx.body = ctx.ok(data)
})
router.post('/create', async ctx => {
await client.namespace_create(ctx.request.body.name)
ctx.body = ctx.ok()
})
router.post('/delete', async ctx => {
await client.namespace_delete(ctx.request.body.name)
ctx.body = ctx.ok()
})
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser');
const yaml = require('js-yaml')
const templates = require('../serviceTemplate')
const client = require('../services/tke.service').create({
secretId: 'AKID4rY7wwNphsUcaFsy1pRtKhQvDj4CA3Ac',
secretKey: 'YBduRnjgVRGzmagZJbss3Vo58wWCyhgc',
clusterId: 'cls-acfx4pvj',
region: 'ap-beijing'
})
const TYPES = ['ui', 'java', 'nodejs', 'python', 'go']
const router = new Router();
module.exports = router
router.use(async (ctx, next) => {
ctx.k8s = client
await next()
}, bodyParser())
router.get('/', async ctx => {
let data = await client.service_list(ctx.query.namespace)
ctx.body = ctx.ok(data)
})
router.post('/create', async ctx => {
let {type, serviceName, namespace, image, system_name} = ctx.request.body
if (!TYPES.includes(type)) {
return ctx.body = ctx.fail('不支持的服务类型')
}
// try {
// let svc = await client.service_get(serviceName, namespace)
// if (svc) {
// return ctx.body = ctx.fail('服务已经存在')
// }
// } catch (e) {
// }
let data = {
serviceName,
namespace,
image,
system_name
}
if (!system_name) {
// ui abTest的时候不一样
data.system_name = serviceName
}
let template = templates[type].replace(/{{([A-Za-z0-9_]+)}}/g, function () {
if (data[arguments[1]] === undefined) {
throw new Error('缺少模板所需变量')
}
return data[arguments[1]]
})
let params = yaml.load(template)
console.log(params)
await client.service_create(params)
ctx.body = ctx.ok(params)
})
router.post('/delete', async ctx => {
let data = await client.service_delete(ctx.request.body.serviceName, ctx.request.body.namespace)
ctx.body = ctx.ok(data)
})
router.post('/modifyImage', async ctx => {
let data = await client.service_modifyImage(ctx.request.body.serviceName, ctx.request.body.image, ctx.request.body.namespace)
ctx.body = ctx.ok(data)
})
const app = require('../app')
app.start()
\ No newline at end of file
...@@ -14,3 +14,9 @@ ui项目,SYSTEM_NAME从环境变量获取,所以需要在nginx.conf中增加 ...@@ -14,3 +14,9 @@ ui项目,SYSTEM_NAME从环境变量获取,所以需要在nginx.conf中增加
abTest的项目,在构建镜像时使用参数CONFIG=abTest/paycenter.conf abTest的项目,在构建镜像时使用参数CONFIG=abTest/paycenter.conf
``` ```
### 问题
1. 把自定义的conf加放到entrypoint中?
感觉就成了config_repository
FROM node:8-alpine
ARG CONFIG=conf/default.js
ARG PROJECT=koa2-hello
ARG TARGET=src/config/
# 拷贝代码
# todo: 从代码镜像中拷贝
ADD code.tar.gz /home/quant_group
# 拷贝配置文件
WORKDIR /home/quant_group/${PROJECT}
COPY ${CONFIG} ${TARGET}
COPY docker-entrypoint.sh ./
CMD ./docker-entrypoint.sh
#!/bin/bash
docker build --build-arg CONFIG=conf/opapi2.js -t test-nodejs .
\ No newline at end of file
moduele.exports = {}
\ No newline at end of file
#!/bin/bash
echo 192.168.4.3 git.q-gp.com >> /etc/hosts
curl -sSL http://git.q-gp.com/QA/qg-docker-entrypoints/raw/tke-ui/tke/nodejs.sh -o run.sh
sh run.sh
# 基于centos7
FROM openresty/openresty:1.13.6.2-centos
COPY nginx.conf /usr/local/openresty/nginx/conf/
WORKDIR /home/quant_group
COPY test-ui.conf ./conf.d/
COPY index.html ./test-ui/
CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]
#!/bin/bash
docker build -t test-ui .
\ No newline at end of file
#!/bin/bash
docker build -t test-ui .
docker tag test-ui ccr.ccs.tencentyun.com/qa-app/test-ui:2
docker push ccr.ccs.tencentyun.com/qa-app/test-ui:2
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title>2222</title>
</head>
<body>
<h1>22222</h1>
</body>
</html>
\ No newline at end of file
#user nobody;
worker_processes 1;
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
#pid logs/nginx.pid;
env SYSTEM_NAME;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
include /home/quant_group/conf.d/*.conf;
}
\ No newline at end of file
server {
listen 80;
server_name _;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 4;
gzip_types text/plain application/x-javascript text/css application/xml application/javascript;
gzip_vary on;
location / {
expires -1;
root /home/quant_group/test-ui;
try_files $uri $uri/ /index.html?$query_string;
}
}
\ No newline at end of file
...@@ -18,10 +18,8 @@ ARG CONFIG=default.conf ...@@ -18,10 +18,8 @@ ARG CONFIG=default.conf
COPY conf/nginx.conf /usr/local/openresty/nginx/conf/ COPY conf/nginx.conf /usr/local/openresty/nginx/conf/
COPY conf/${CONFIG} /etc/nginx/conf.d/ COPY conf/${CONFIG} /etc/nginx/conf.d/
# 拷贝代码, code/xjd-ui/dist
# 先打包好代码镜像,然后从镜像中拷贝??
COPY code .
COPY docker-entrypoint.sh ./
CMD ./docker-entrypoint.sh # COPY docker-entrypoint.sh ./
# CMD ./docker-entrypoint.sh
#!/bin/bash #!/bin/bash
tag=2.3 tag=2.4
docker build -t test-ui . && docker tag test-ui 192.168.4.4/tmp/test-ui:${tag} && docker push 192.168.4.4/tmp/test-ui:${tag} docker build -t test-ui .
\ No newline at end of file # && docker tag test-ui 192.168.4.4/tmp/test-ui:${tag} && docker push 192.168.4.4/tmp/test-ui:${tag}
\ No newline at end of file
...@@ -33,5 +33,5 @@ http { ...@@ -33,5 +33,5 @@ http {
#gzip on; #gzip on;
include /etc/nginx/conf.d/*.conf; include /home/quant_group/conf.d/*.conf;
} }
\ No newline at end of file
'use strict'
// const logger = require('koa-log4').getLogger('middleware:error')
module.exports = function () {
return async function (ctx, next) {
try {
await next()
} catch (e) {
let msg = '系统出错了哦,请稍后再试。'
// mongo 唯一索引冲突
if (e.name === 'MongoError') {
msg = e.errmsg
} else if (e.message) {
msg = e.message
}
console.error(ctx.path)
console.error(e)
ctx.respond = true
ctx.status = 200
ctx.body = {
code: '0001',
msg: msg
}
}
}
}
'use strict'
/**
*/
module.exports = {
// 通用参数错误
ERROR_INPUT: { msg: '输入参数不正确', code: '0001' },
// 自定义参数错误
ERROR_GITPATH: { msg: 'git_path格式不正确', code: '0001' }
}
'use strict'
const Code = require('./code')
module.exports = function () {
return async function (ctx, next) {
if (ctx.ok || ctx.fail) return next()
ctx.ok = function (data = {}) {
return {
code: '0000',
data: data
}
}
ctx.Code = Code
ctx.fail = function (msg, code) {
if (msg && msg.code) {
return msg
}
return {
code: code || '0001',
msg: msg || '请求失败,请稍候重试'
}
}
return next()
}
}
{
"delay": "2500",
"ignore": ["*.test.js", "fixtures/*"],
"ext": "js json txt"
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "tke-eos",
"version": "1.0.0",
"description": "",
"main": "bin/www.js",
"dependencies": {
"js-yaml": "^3.12.1",
"koa": "^2.6.2",
"koa-bodyparser": "^4.2.1",
"koa-router": "^7.4.0",
"lodash": "^4.17.11",
"nodemon": "^1.18.9",
"tencentcloud-sdk-nodejs": "^3.0.43"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "NODE_DEBUG nodemon"
},
"repository": {
"type": "git",
"url": "git@git.quantgroup.cn:QA/tke-eos.git"
},
"keywords": [],
"author": "",
"license": "ISC"
}
const fs = require('fs')
console.log(process.cwd())
const ui = fs.readFileSync('serviceTemplate/ui.template.txt', 'utf8')
module.exports = {
ui
}
\ No newline at end of file
serviceName: {{serviceName}}
namespace: {{namespace}}
replicas: 1
revisionHistoryLimit: 2
accessType: ClusterIP
portMappings.0.protocol: TCP
portMappings.0.lbPort: 80
portMappings.0.containerPort: 80
containers.0.containerName: {{system_name}}
containers.0.image: {{image}}
containers.0.envs.0.name: SYSTEM_NAME
containers.0.envs.0.value: {{system_name}}
containers.0.envs.1.name: NAMESPACE
containers.0.envs.1.value: {{namespace}}
\ No newline at end of file
const request = require('request')
const crypto = require('crypto')
class Client {
constructor ({secretId, secretKey, region, clusterId}) {
this.secretId = secretId
this.secretKey = secretKey
this.region = region
this.clusterId = clusterId
this.method = 'POST'
this.protocal = 'https://'
this.endpoint = 'ccs.api.qcloud.com'
this.path = '/v2/index.php'
// 禁止操作以下命名空间
this.ReservedNamespace = ['default', 'kube-system']
}
sign (params, signMethod) {
let str = ''
let keys = Object.keys(params)
keys.sort()
for (let key of keys) {
str += '&' + key + '=' + params[key]
}
str = str.slice(1)
let signStr = this.method + this.endpoint + this.path + '?' + str
let signMethodMap = {
HmacSHA1: "sha1",
HmacSHA256: "sha256"
}
let hmac = crypto.createHmac(signMethodMap[signMethod], this.secretKey)
return hmac.update(Buffer.from(signStr, 'utf-8')).digest('base64')
}
// 公共参数
// Action: '',
// Region: '',
// Timestamp: null,
// Nonce: null,
// SecretId: '',
// Signature: ''
formatRequestData (action, params = {}) {
params.Action = action
params.Region = this.region
params.Timestamp = Math.round(Date.now() / 1000)
params.Nonce = Math.round(Math.random() * 65535)
params.SecretId = this.secretId
params.SignatureMethod = params.SignatureMethod || 'HmacSHA256'
params.Signature = this.sign(params, params.SignatureMethod)
}
post (action, params = {}) {
if (params.namespace && this.ReservedNamespace.includes(params.namespace)) {
return Promise.reject(new Error('未授权的namespace'))
}
this.formatRequestData(action, params)
let url = this.protocal + this.endpoint + this.path
let self = this
return new Promise(function (resolve, reject) {
request({
method: self.method,
url,
json: true,
form: params
}, function (err, res, body) {
if (err) {
console.error(err)
reject(err)
} else {
if (body.code === 0) {
resolve(body.data)
} else {
reject(body)
}
}
})
})
}
doGet (action, params = {}) {
if (params.namespace && this.ReservedNamespace.includes(params.namespace)) {
return Promise.reject(new Error('未授权的namespace'))
}
this.formatRequestData(action, params)
let url = this.protocal + this.endpoint + this.path
let self = this
return new Promise(function (resolve, reject) {
request({
method: 'GET',
url,
json: true,
qs: params
}, function (err, res, body) {
if (err) {
console.error(err)
reject(err)
} else {
if (body.code === 0) {
resolve(body.data)
} else {
reject(body)
}
}
})
})
}
namespace_get () {
return this.post('DescribeClusterNameSpaces', {clusterId: this.clusterId})
}
namespace_create (name) {
return this.post('CreateClusterNamespace', {name, description: '', clusterId: this.clusterId})
}
namespace_delete (name) {
return this.post('DeleteClusterNamespace', {"names.0": name, clusterId: this.clusterId})
}
service_list (namespace) {
return this.post('DescribeClusterService', {namespace, clusterId: this.clusterId, allnamespace: 0})
}
service_get (serviceName, namespace) {
return this.post('DescribeClusterServiceInfo', {serviceName, namespace, clusterId: this.clusterId})
}
async service_create (params) {
await this.post('CreateClusterService', {clusterId: this.clusterId, ...params})
// 腾讯云api暂只能通过修改服务来改成Recreate策略
let modifyParams = {
clusterId: this.clusterId,
serviceName: params.serviceName,
namespace: params.namespace,
strategy: 'Reacreate'
}
return this.post('ModifyClusterService', modifyParams)
}
service_delete (serviceName, namespace) {
return this.post('DeleteClusterService', {serviceName, namespace, clusterId: this.clusterId})
}
service_modifyImage (serviceName, image, namespace) {
// 修改示例的第一个容器
return this.post('ModifyClusterServiceImage', {serviceName, namespace, image, clusterId: this.clusterId})
}
}
exports.create = function (config) {
return new Client(config)
}
// let client = new Client({
// secretId: 'AKID4rY7wwNphsUcaFsy1pRtKhQvDj4CA3Ac',
// secretKey: 'YBduRnjgVRGzmagZJbss3Vo58wWCyhgc',
// clusterId: 'cls-acfx4pvj',
// region: 'ap-beijing'
// })
// client.post('DescribeClusterNameSpaces', {clusterId: 'cls-acfx4pvj'}).then(res => {
// console.log(5, res)
// })
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment