├── .gitignore ├── .prettierrc ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── deploys ├── configmap-other.yaml ├── configmap.yaml ├── deployment.yaml ├── rbac.yaml └── service.yaml ├── nodemon-debug.json ├── nodemon.json ├── package.json ├── src ├── app.module.ts ├── clients │ ├── ArticleClient.ts │ ├── UserClient.ts │ └── index.ts ├── config.yaml ├── controllers │ ├── ArticleController.ts │ ├── ProxyController.ts │ ├── UserController.ts │ └── index.ts ├── main.ts └── services │ ├── ScheduleService.ts │ └── index.ts ├── test ├── app.e2e-spec.ts └── jest-e2e.json ├── tsconfig.build.json ├── tsconfig.json ├── tsconfig.spec.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/**/workspace.xml 8 | .idea/**/tasks.xml 9 | .idea/dictionaries 10 | 11 | # Sensitive or high-churn files: 12 | .idea/**/dataSources/ 13 | .idea/**/dataSources.ids 14 | .idea/**/dataSources.xml 15 | .idea/**/dataSources.local.xml 16 | .idea/**/sqlDataSources.xml 17 | .idea/**/dynamic.xml 18 | .idea/**/uiDesigner.xml 19 | 20 | # Gradle: 21 | .idea/**/gradle.xml 22 | .idea/**/libraries 23 | 24 | # CMake 25 | cmake-build-debug/ 26 | 27 | # Mongo Explorer plugin: 28 | .idea/**/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.iws 32 | 33 | ## Plugin-specific files: 34 | 35 | # IntelliJ 36 | out/ 37 | 38 | # mpeltonen/sbt-idea plugin 39 | .idea_modules/ 40 | 41 | # JIRA plugin 42 | atlassian-ide-plugin.xml 43 | 44 | # Cursive Clojure plugin 45 | .idea/replstate.xml 46 | 47 | # Crashlytics plugin (for Android Studio and IntelliJ) 48 | com_crashlytics_export_strings.xml 49 | crashlytics.properties 50 | crashlytics-build.properties 51 | fabric.properties 52 | ### VisualStudio template 53 | ## Ignore Visual Studio temporary files, build results, and 54 | ## files generated by popular Visual Studio add-ons. 55 | ## 56 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 57 | 58 | # User-specific files 59 | *.suo 60 | *.user 61 | *.userosscache 62 | *.sln.docstates 63 | 64 | # User-specific files (MonoDevelop/Xamarin Studio) 65 | *.userprefs 66 | 67 | # Build results 68 | [Dd]ebug/ 69 | [Dd]ebugPublic/ 70 | [Rr]elease/ 71 | [Rr]eleases/ 72 | x64/ 73 | x86/ 74 | bld/ 75 | [Bb]in/ 76 | [Oo]bj/ 77 | [Ll]og/ 78 | 79 | # Visual Studio 2015 cache/options directory 80 | .vs/ 81 | # Uncomment if you have tasks that create the project's static files in wwwroot 82 | #wwwroot/ 83 | 84 | # MSTest test Results 85 | [Tt]est[Rr]esult*/ 86 | [Bb]uild[Ll]og.* 87 | 88 | # NUNIT 89 | *.VisualState.xml 90 | TestResult.xml 91 | 92 | # Build Results of an ATL Project 93 | [Dd]ebugPS/ 94 | [Rr]eleasePS/ 95 | dlldata.c 96 | 97 | # Benchmark Results 98 | BenchmarkDotNet.Artifacts/ 99 | 100 | # .NET Core 101 | project.lock.json 102 | project.fragment.lock.json 103 | artifacts/ 104 | **/Properties/launchSettings.json 105 | 106 | *_i.c 107 | *_p.c 108 | *_i.h 109 | *.ilk 110 | *.meta 111 | *.obj 112 | *.pch 113 | *.pdb 114 | *.pgc 115 | *.pgd 116 | *.rsp 117 | *.sbr 118 | *.tlb 119 | *.tli 120 | *.tlh 121 | *.tmp 122 | *.tmp_proj 123 | *.log 124 | *.vspscc 125 | *.vssscc 126 | .builds 127 | *.pidb 128 | *.svclog 129 | *.scc 130 | 131 | # Chutzpah Test files 132 | _Chutzpah* 133 | 134 | # Visual C++ cache files 135 | ipch/ 136 | *.aps 137 | *.ncb 138 | *.opendb 139 | *.opensdf 140 | *.sdf 141 | *.cachefile 142 | *.VC.db 143 | *.VC.VC.opendb 144 | 145 | # Visual Studio profiler 146 | *.psess 147 | *.vsp 148 | *.vspx 149 | *.sap 150 | 151 | # Visual Studio Trace Files 152 | *.e2e 153 | 154 | # TFS 2012 Local Workspace 155 | $tf/ 156 | 157 | # Guidance Automation Toolkit 158 | *.gpState 159 | 160 | # ReSharper is a .NET coding add-in 161 | _ReSharper*/ 162 | *.[Rr]e[Ss]harper 163 | *.DotSettings.user 164 | 165 | # JustCode is a .NET coding add-in 166 | .JustCode 167 | 168 | # TeamCity is a build add-in 169 | _TeamCity* 170 | 171 | # DotCover is a Code Coverage Tool 172 | *.dotCover 173 | 174 | # AxoCover is a Code Coverage Tool 175 | .axoCover/* 176 | !.axoCover/settings.json 177 | 178 | # Visual Studio code coverage results 179 | *.coverage 180 | *.coveragexml 181 | 182 | # NCrunch 183 | _NCrunch_* 184 | .*crunch*.local.xml 185 | nCrunchTemp_* 186 | 187 | # MightyMoose 188 | *.mm.* 189 | AutoTest.Net/ 190 | 191 | # Web workbench (sass) 192 | .sass-cache/ 193 | 194 | # Installshield output folder 195 | [Ee]xpress/ 196 | 197 | # DocProject is a documentation generator add-in 198 | DocProject/buildhelp/ 199 | DocProject/Help/*.HxT 200 | DocProject/Help/*.HxC 201 | DocProject/Help/*.hhc 202 | DocProject/Help/*.hhk 203 | DocProject/Help/*.hhp 204 | DocProject/Help/Html2 205 | DocProject/Help/html 206 | 207 | # Click-Once directory 208 | publish/ 209 | 210 | # Publish Web Output 211 | *.[Pp]ublish.xml 212 | *.azurePubxml 213 | # Note: Comment the next line if you want to checkin your web deploy settings, 214 | # but database connection strings (with potential passwords) will be unencrypted 215 | *.pubxml 216 | *.publishproj 217 | 218 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 219 | # checkin your Azure Web App publish settings, but sensitive information contained 220 | # in these scripts will be unencrypted 221 | PublishScripts/ 222 | 223 | # NuGet Packages 224 | *.nupkg 225 | # The packages folder can be ignored because of Package Restore 226 | **/[Pp]ackages/* 227 | # except build/, which is used as an MSBuild target. 228 | !**/[Pp]ackages/build/ 229 | # Uncomment if necessary however generally it will be regenerated when needed 230 | #!**/[Pp]ackages/repositories.config 231 | # NuGet v3's project.json files produces more ignorable files 232 | *.nuget.props 233 | *.nuget.targets 234 | 235 | # Microsoft Azure Build Output 236 | csx/ 237 | *.build.csdef 238 | 239 | # Microsoft Azure Emulator 240 | ecf/ 241 | rcf/ 242 | 243 | # Windows Store app package directories and files 244 | AppPackages/ 245 | BundleArtifacts/ 246 | Package.StoreAssociation.xml 247 | _pkginfo.txt 248 | *.appx 249 | 250 | # Visual Studio cache files 251 | # files ending in .cache can be ignored 252 | *.[Cc]ache 253 | # but keep track of directories ending in .cache 254 | !*.[Cc]ache/ 255 | 256 | # Others 257 | ClientBin/ 258 | ~$* 259 | *~ 260 | *.dbmdl 261 | *.dbproj.schemaview 262 | *.jfm 263 | *.pfx 264 | *.publishsettings 265 | orleans.codegen.cs 266 | 267 | # Since there are multiple workflows, uncomment next line to ignore bower_components 268 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 269 | #bower_components/ 270 | 271 | # RIA/Silverlight projects 272 | Generated_Code/ 273 | 274 | # Backup & report files from converting an old project file 275 | # to a newer Visual Studio version. Backup files are not needed, 276 | # because we have git ;-) 277 | _UpgradeReport_Files/ 278 | Backup*/ 279 | UpgradeLog*.XML 280 | UpgradeLog*.htm 281 | 282 | # SQL Server files 283 | *.mdf 284 | *.ldf 285 | *.ndf 286 | 287 | # Business Intelligence projects 288 | *.rdl.data 289 | *.bim.layout 290 | *.bim_*.settings 291 | 292 | # Microsoft Fakes 293 | FakesAssemblies/ 294 | 295 | # GhostDoc plugin setting file 296 | *.GhostDoc.xml 297 | 298 | # Node.js Tools for Visual Studio 299 | .ntvs_analysis.dat 300 | node_modules/ 301 | 302 | # Typescript v1 declaration files 303 | typings/ 304 | 305 | # Visual Studio 6 build log 306 | *.plg 307 | 308 | # Visual Studio 6 workspace options file 309 | *.opt 310 | 311 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 312 | *.vbw 313 | 314 | # Visual Studio LightSwitch build output 315 | **/*.HTMLClient/GeneratedArtifacts 316 | **/*.DesktopClient/GeneratedArtifacts 317 | **/*.DesktopClient/ModelManifest.xml 318 | **/*.Server/GeneratedArtifacts 319 | **/*.Server/ModelManifest.xml 320 | _Pvt_Extensions 321 | 322 | # Paket dependency manager 323 | .paket/paket.exe 324 | paket-files/ 325 | 326 | # FAKE - F# Make 327 | .fake/ 328 | 329 | # JetBrains Rider 330 | .idea/ 331 | *.sln.iml 332 | 333 | # CodeRush 334 | .cr/ 335 | 336 | # Python Tools for Visual Studio (PTVS) 337 | __pycache__/ 338 | *.pyc 339 | 340 | # Cake - Uncomment if you are using it 341 | # tools/** 342 | # !tools/packages.config 343 | 344 | # Tabs Studio 345 | *.tss 346 | 347 | # Telerik's JustMock configuration file 348 | *.jmconfig 349 | 350 | # BizTalk build output 351 | *.btp.cs 352 | *.btm.cs 353 | *.odx.cs 354 | *.xsd.cs 355 | 356 | # OpenCover UI analysis results 357 | OpenCover/ 358 | coverage/ 359 | 360 | ### macOS template 361 | # General 362 | .DS_Store 363 | .AppleDouble 364 | .LSOverride 365 | 366 | # Icon must end with two \r 367 | Icon 368 | 369 | # Thumbnails 370 | ._* 371 | 372 | # Files that might appear in the root of a volume 373 | .DocumentRevisions-V100 374 | .fseventsd 375 | .Spotlight-V100 376 | .TemporaryItems 377 | .Trashes 378 | .VolumeIcon.icns 379 | .com.apple.timemachine.donotpresent 380 | 381 | # Directories potentially created on remote AFP share 382 | .AppleDB 383 | .AppleDesktop 384 | Network Trash Folder 385 | Temporary Items 386 | .apdisk 387 | 388 | ======= 389 | # Local 390 | docker-compose.yml 391 | .env 392 | build 393 | logs 394 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10.16.0-alpine 2 | 3 | WORKDIR /opt/app 4 | 5 | COPY build build/ 6 | COPY node_modules node_modules/ 7 | 8 | ENV NODE_ENV production 9 | 10 | EXPOSE 3200 11 | CMD [ "node", "./build/main.js" ] 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2017-2019 Kamil Myśliwiec 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | IMAGE_NAME=nestcloud/nestcloud-kubernetes-example 2 | IMAGE_VERSION=1.1.2 3 | 4 | 5 | build: 6 | yarn 7 | npm run build 8 | image: 9 | yarn 10 | npm run build 11 | yarn install --production 12 | docker build -t $(IMAGE_NAME):$(IMAGE_VERSION) . 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [travis-image]: https://api.travis-ci.org/nest-cloud/nestcloud.svg?branch=master 3 | [travis-url]: https://travis-ci.org/nest-cloud/nestcloud 4 | [linux-image]: https://img.shields.io/travis/nest-cloud/nestcloud/master.svg?label=linux 5 | [linux-url]: https://travis-ci.org/nest-cloud/nestcloud 6 | 7 | # NestCloud 8 | 9 |

10 | NPM Version 11 | Package License 12 | NPM Downloads 13 | Travis 14 | Linux 15 | Coverage 16 |

17 | 18 | How run nestcloud app in kubernetes cluster. 19 | 20 | ## Requirement Modules 21 | 22 | * @nestcloud/boot 23 | * @nestcloud/http 24 | 25 | 26 | ## Optional Modules 27 | 28 | * @nestcloud/kubernetes 29 | * @nestcloud/config 30 | 31 | 32 | ## Build 33 | ```bash 34 | make image 35 | 36 | ``` 37 | 38 | ## Deploy 39 | 40 | ```bash 41 | kubectl create -f ./deploys/configmap.yaml 42 | kubectl create -f ./deploys/configmap-other.yaml 43 | kubectl create -f ./deploys/rbac.yaml 44 | kubectl create -f ./deploys/deployment.yaml 45 | kubectl create -f ./deploys/service.yaml 46 | 47 | ``` 48 | 49 | ## Stay in touch 50 | 51 | - Author - [Miaowing](https://github.com/miaowing) 52 | 53 | ## License 54 | 55 | Nest is [MIT licensed](LICENSE). 56 | -------------------------------------------------------------------------------- /deploys/configmap-other.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | config.yaml: |- 4 | data: 5 | test: get config data from other config map. 6 | 7 | kind: ConfigMap 8 | metadata: 9 | name: nestcloud-kubernetes-config 10 | namespace: default 11 | -------------------------------------------------------------------------------- /deploys/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | config.yaml: |- 4 | config: 5 | name: nestcloud-kubernetes-config 6 | namespace: default 7 | path: config.yaml 8 | service: 9 | name: nestcloud-kubernetes-example 10 | port: 3200 11 | proxy: 12 | routes: 13 | - id: user 14 | # self 15 | uri: http://nestcloud-kubernetes-example 16 | - id: article 17 | uri: https://api.apiopen.top/recommendPoetry 18 | logger: 19 | level: debug 20 | transports: 21 | - transport: console 22 | colorize: true 23 | datePattern: YYYY-MM-DD HH:mm:ss 24 | label: ${{ service.name }} 25 | - transport: dailyRotateFile 26 | label: ${{ service.name }} 27 | filename: ../logs/${{ service.name }}-%DATE%.log 28 | datePattern: YYYY-MM-DD-HH 29 | zippedArchive: true 30 | maxSize: 20m 31 | maxFiles: 14d 32 | 33 | kind: ConfigMap 34 | metadata: 35 | name: nestcloud-kubernetes-example-conf 36 | namespace: default 37 | -------------------------------------------------------------------------------- /deploys/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta2 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: nestcloud-kubernetes-example 6 | name: nestcloud-kubernetes-example 7 | namespace: default 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: nestcloud-kubernetes-example 13 | template: 14 | metadata: 15 | labels: 16 | app: nestcloud-kubernetes-example 17 | spec: 18 | containers: 19 | - image: nestcloud/nestcloud-kubernetes-example:1.1.2 20 | imagePullPolicy: IfNotPresent 21 | name: proxy 22 | resources: {} 23 | env: 24 | - name: NODE_ENV 25 | value: production 26 | - name: RUNTIME 27 | value: kubernetes 28 | volumeMounts: 29 | - mountPath: /opt/app/build/config.yaml 30 | name: volume-config 31 | subPath: config.yaml 32 | volumes: 33 | - configMap: 34 | items: 35 | - key: config.yaml 36 | path: config.yaml 37 | name: nestcloud-kubernetes-example-conf 38 | name: volume-config 39 | serviceAccountName: nestcloud-kubernetes-example-account 40 | -------------------------------------------------------------------------------- /deploys/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: nestcloud-kubernetes-example-account 6 | namespace: default 7 | --- 8 | kind: ClusterRole 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | metadata: 11 | name: nestcloud-kubernetes-example-role 12 | rules: 13 | - apiGroups: [""] 14 | resources: ["configmaps"] 15 | verbs: ["get", "list", "delete", "create", "patch", "watch"] 16 | - apiGroups: ["*"] 17 | resources: ["*"] 18 | verbs: ["get", "list"] 19 | --- 20 | kind: ClusterRoleBinding 21 | apiVersion: rbac.authorization.k8s.io/v1 22 | metadata: 23 | name: nestcloud-kubernetes-example-role-binding 24 | subjects: 25 | - kind: ServiceAccount 26 | name: nestcloud-kubernetes-example-account 27 | namespace: default 28 | roleRef: 29 | kind: ClusterRole 30 | name: nestcloud-kubernetes-example-role 31 | apiGroup: rbac.authorization.k8s.io 32 | -------------------------------------------------------------------------------- /deploys/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: nestcloud-kubernetes-example-service 5 | namespace: default 6 | spec: 7 | ports: 8 | - port: 80 9 | protocol: TCP 10 | targetPort: 3200 11 | selector: 12 | app: nestcloud-kubernetes-example 13 | type: ClusterIP 14 | -------------------------------------------------------------------------------- /nodemon-debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": ["src/**/*.spec.ts"], 5 | "exec": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register src/main.ts" 6 | } -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": ["src/**/*.spec.ts"], 5 | "exec": "ts-node -r tsconfig-paths/register src/main.ts" 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nest-cloud-starter", 3 | "version": "1.0.0", 4 | "description": "NestCloud TypeScript starter repository", 5 | "license": "MIT", 6 | "scripts": { 7 | "build": "tsc -p tsconfig.build.json", 8 | "format": "prettier --write \"src/**/*.ts\"", 9 | "start": "ts-node -r tsconfig-paths/register src/main.ts", 10 | "start:dev": "nodemon", 11 | "start:debug": "nodemon --config nodemon-debug.json", 12 | "prestart:prod": "rimraf dist && tsc", 13 | "start:prod": "node dist/main.js", 14 | "lint": "tslint -p tsconfig.json -c tslint.json", 15 | "test": "jest", 16 | "test:watch": "jest --watch", 17 | "test:cov": "jest --coverage", 18 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 19 | "test:e2e": "jest --config ./test/jest-e2e.json" 20 | }, 21 | "dependencies": { 22 | "@godaddy/terminus": "^4.1.0", 23 | "@nestcloud/boot": "^0.7.13", 24 | "@nestcloud/common": "^0.7.13", 25 | "@nestcloud/config": "^0.7.4", 26 | "@nestcloud/http": "^0.7.13", 27 | "@nestcloud/kubernetes": "^0.7.13", 28 | "@nestcloud/loadbalance": "^0.7.13", 29 | "@nestcloud/logger": "^0.7.13", 30 | "@nestcloud/proxy": "^0.7.13", 31 | "@nestcloud/schedule": "^0.7.13", 32 | "@nestjs/common": "^6.5.3", 33 | "@nestjs/core": "^6.5.3", 34 | "@nestjs/microservices": "^6.5.3", 35 | "@nestjs/platform-express": "^6.5.3", 36 | "@nestjs/swagger": "^3.0.1", 37 | "@nestjs/terminus": "^6.5.0", 38 | "@nestjs/testing": "^6.5.3", 39 | "@nestjs/typeorm": "^6.0.0", 40 | "@nestjs/websockets": "^6.5.3", 41 | "reflect-metadata": "^0.1.12", 42 | "rimraf": "^2.6.2", 43 | "rxjs": "^6.3.3", 44 | "rxjs-compat": "^6.3.3" 45 | }, 46 | "devDependencies": { 47 | "@types/express": "^4.16.0", 48 | "@types/jest": "^23.3.1", 49 | "@types/node": "^10.7.1", 50 | "@types/supertest": "^2.0.5", 51 | "@types/winston": "^2.4.4", 52 | "jest": "^23.5.0", 53 | "nodemon": "^1.18.3", 54 | "prettier": "^1.14.2", 55 | "supertest": "^3.1.0", 56 | "ts-jest": "^23.1.3", 57 | "ts-node": "^7.0.1", 58 | "tsconfig-paths": "^3.7.0", 59 | "tslint": "5.11.0", 60 | "typescript": "^3.8.3" 61 | }, 62 | "jest": { 63 | "moduleFileExtensions": [ 64 | "js", 65 | "json", 66 | "ts" 67 | ], 68 | "rootDir": "src", 69 | "testRegex": ".spec.ts$", 70 | "transform": { 71 | "^.+\\.(t|j)s$": "ts-jest" 72 | }, 73 | "coverageDirectory": "../coverage", 74 | "testEnvironment": "node" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { BootModule } from '@nestcloud/boot'; 3 | import { ConfigModule } from '@nestcloud/config'; 4 | import { HttpModule } from '@nestcloud/http'; 5 | import { ScheduleModule } from '@nestcloud/schedule'; 6 | import { BOOT, components, KUBERNETES, LOADBALANCE } from '@nestcloud/common'; 7 | import { TypeOrmHealthIndicator, TerminusModule, TerminusModuleOptions } from '@nestjs/terminus'; 8 | import { ProxyModule } from '@nestcloud/proxy'; 9 | 10 | import * as controllers from './controllers'; 11 | import * as services from './services'; 12 | import * as clients from './clients'; 13 | import { LoggerModule } from '@nestcloud/logger'; 14 | import { resolve } from 'path'; 15 | import { KubernetesModule } from '@nestcloud/kubernetes'; 16 | 17 | const getTerminusOptions = (db: TypeOrmHealthIndicator): TerminusModuleOptions => ({ 18 | endpoints: [ 19 | { 20 | url: '/health', 21 | healthIndicators: [ 22 | async () => db.pingCheck('database', { timeout: 300 }), 23 | ], 24 | }, 25 | ], 26 | }); 27 | 28 | @Module({ 29 | imports: [ 30 | LoggerModule.forRoot(), 31 | ScheduleModule.forRoot(), 32 | BootModule.forRoot({ filePath: resolve(__dirname, 'config.yaml') }), 33 | ConfigModule.forRootAsync({ inject: [KUBERNETES, BOOT] }), 34 | HttpModule.forRoot(), 35 | ProxyModule.forRootAsync({ inject: [BOOT] }), 36 | KubernetesModule.forRootAsync({ inject: [BOOT] }), 37 | TerminusModule.forRootAsync({ 38 | inject: [TypeOrmHealthIndicator], 39 | useFactory: db => getTerminusOptions(db as TypeOrmHealthIndicator), 40 | }), 41 | ], 42 | controllers: components(controllers), 43 | providers: components(services, clients), 44 | }) 45 | export class AppModule { 46 | } 47 | -------------------------------------------------------------------------------- /src/clients/ArticleClient.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { Get } from '@nestcloud/http'; 3 | 4 | @Injectable() 5 | export class ArticleClient { 6 | @Get('https://api.apiopen.top/recommendPoetry') 7 | getArticles() { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/clients/UserClient.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { Get } from '@nestcloud/http'; 3 | import { Loadbalanced } from '@nestcloud/loadbalance'; 4 | 5 | @Injectable() 6 | @Loadbalanced('nestcloud-kubernetes-example') 7 | export class UserClient { 8 | @Get('/users') 9 | async getUsers(): Promise { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/clients/index.ts: -------------------------------------------------------------------------------- 1 | export * from './UserClient'; 2 | export * from './ArticleClient'; 3 | -------------------------------------------------------------------------------- /src/config.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | name: nestcloud-kubernetes-config 3 | namespace: default 4 | path: config.yaml 5 | service: 6 | name: nestcloud-kubernetes-example 7 | port: 3200 8 | proxy: 9 | routes: 10 | - id: user 11 | # self 12 | uri: http://nestcloud-kubernetes-example 13 | - id: article 14 | uri: https://api.apiopen.top/recommendPoetry 15 | kubernetes: 16 | kubeConfig: /Users/zhaofeng/.kube/config 17 | logger: 18 | level: debug 19 | transports: 20 | - transport: console 21 | colorize: true 22 | datePattern: YYYY-MM-DD HH:mm:ss 23 | label: ${{ service.name }} 24 | - transport: dailyRotateFile 25 | label: ${{ service.name }} 26 | filename: ../logs/${{ service.name }}-%DATE%.log 27 | datePattern: YYYY-MM-DD-HH 28 | zippedArchive: true 29 | maxSize: 20m 30 | maxFiles: 14d 31 | -------------------------------------------------------------------------------- /src/controllers/ArticleController.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { ArticleClient } from '../clients'; 3 | 4 | @Controller('articles') 5 | export class ArticleController { 6 | constructor( 7 | private readonly articleClient: ArticleClient, 8 | ) { 9 | } 10 | 11 | @Get() 12 | async getArticles() { 13 | return this.articleClient.getArticles(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/controllers/ProxyController.ts: -------------------------------------------------------------------------------- 1 | import { All, Controller, Param, Req, Res } from '@nestjs/common'; 2 | import { Request, Response } from 'express'; 3 | import { Proxy, InjectProxy } from '@nestcloud/proxy'; 4 | 5 | @Controller('/proxy/:service') 6 | export class ProxyController { 7 | constructor( 8 | @InjectProxy() private readonly proxy: Proxy, 9 | ) { 10 | } 11 | 12 | @All() 13 | async do(@Req() req: Request, @Res() res: Response, @Param('service') id) { 14 | await this.proxy.forward(req, res, id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/controllers/UserController.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Query, Req } from '@nestjs/common'; 2 | 3 | @Controller('users') 4 | export class UserController { 5 | @Get() 6 | async getUsers(@Query('remote') isRemote: boolean, @Req() req) { 7 | return [{ id: 1, name: 'John' }, { id: 2, name: 'Sarah' }]; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/controllers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './UserController'; 2 | export * from './ArticleController'; 3 | export * from './ProxyController'; 4 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | import { NestLogger } from '@nestcloud/logger'; 4 | import { resolve } from 'path'; 5 | import { BOOT, IBoot } from '@nestcloud/common'; 6 | 7 | async function bootstrap() { 8 | const app = await NestFactory.create(AppModule, { 9 | logger: new NestLogger({ filePath: resolve(__dirname, 'config.yaml') }), 10 | }); 11 | 12 | process.on('SIGINT', async () => { 13 | setTimeout(() => process.exit(1), 5000); 14 | await app.close(); 15 | process.exit(0); 16 | }); 17 | 18 | // kill -15 19 | process.on('SIGTERM', async () => { 20 | setTimeout(() => process.exit(1), 5000); 21 | await app.close(); 22 | process.exit(0); 23 | }); 24 | 25 | const boot = app.get(BOOT); 26 | await app.listen(boot.get('service.port', 3200)); 27 | } 28 | 29 | bootstrap(); 30 | -------------------------------------------------------------------------------- /src/services/ScheduleService.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Logger } from '@nestjs/common'; 2 | import { Interval } from '@nestcloud/schedule'; 3 | import { InjectLogger } from '@nestcloud/logger'; 4 | import { BootValue } from '@nestcloud/boot'; 5 | import { ConfigValue } from '@nestcloud/config'; 6 | 7 | @Injectable() 8 | export class ScheduleService { 9 | @BootValue('service.name', 'default service name') 10 | private readonly serviceName: string; 11 | 12 | @ConfigValue('data.test', 'default custom data') 13 | private readonly configMapData: string; 14 | 15 | public constructor( 16 | @InjectLogger() private readonly logger: Logger, 17 | ) { 18 | } 19 | 20 | @Interval(2000) 21 | intervalBootJob() { 22 | this.logger.log('interval get service name from boot: ' + this.serviceName); 23 | } 24 | 25 | @Interval(2000) 26 | intervalConsulConfigJob() { 27 | this.logger.log('interval get data from k8s configMap: ' + this.configMapData); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ScheduleService'; 2 | -------------------------------------------------------------------------------- /test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import * as request from 'supertest'; 2 | import { Test } from '@nestjs/testing'; 3 | import { AppModule } from '../src/app.module'; 4 | import { INestApplication } from '@nestjs/common'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | // @ts-ignore 10 | beforeAll(async () => { 11 | const moduleFixture = await Test.createTestingModule({ 12 | imports: [AppModule], 13 | }).compile(); 14 | 15 | app = moduleFixture.createNestApplication(); 16 | await app.init(); 17 | }); 18 | 19 | it('/users (GET)', () => { 20 | return request(app.getHttpServer()) 21 | .get('/users') 22 | .expect(200); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*"], 4 | "exclude": ["node_modules", "**/*.spec.ts"] 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": false, 5 | "noImplicitAny": false, 6 | "removeComments": true, 7 | "noLib": false, 8 | "allowSyntheticDefaultImports": true, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es6", 12 | "sourceMap": true, 13 | "allowJs": true, 14 | "outDir": "./build", 15 | "baseUrl": "./src", 16 | "skipLibCheck": true 17 | }, 18 | "include": [ 19 | "src/**/*" 20 | ], 21 | "exclude": [ 22 | "node_modules", 23 | "**/*.spec.ts" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["jest", "node"] 5 | }, 6 | "include": ["**/*.spec.ts", "**/*.d.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended"], 4 | "jsRules": { 5 | "no-unused-expression": true 6 | }, 7 | "rules": { 8 | "no-empty": false, 9 | "quotemark": [true, "single"], 10 | "member-access": [false], 11 | "ordered-imports": [false], 12 | "max-line-length": [true, 150], 13 | "member-ordering": [false], 14 | "interface-name": [false], 15 | "arrow-parens": false, 16 | "object-literal-sort-keys": false 17 | }, 18 | "rulesDirectory": [] 19 | } 20 | --------------------------------------------------------------------------------