GithubHelp home page GithubHelp logo

jenkins-pipeline-nodejs's Introduction

Jenkins pipeline library for Nodejs deployment

This is Jenkins pipeline we that are using for the deployment of Nodejs applications to the GKE clusters. It's meant to be simple and straightforward. It also addresses secrets management with Hashicorp's Vault so you can store your passwords, API keys etc. in the secure store and leverage functionality of Nodejs libraries such as dotenv (or similar) to maintain configuration variables in the different application environments.

Requirements for your Jenkins workers

Software

This pipeline is using variety of third party software. Please make sure your Jenkins worker has following binaries in the PATH:

  • helm (pipeline has been tested with 2.11.0)
  • docker-compose (pipeline has been tested with 1.23.1)
  • vault (pipeline has been tested with 0.11.4)

Kubeconfig naming convention

Each configured environment in the Jenkinsfile can have kubeConfigPath option populated in the Jenkinsfile. It's the full path of the kubeconfig for the given cluster. However you can also use the automated kubeconfig name resolution, in this case you need to save kubeconfigs in the following format:

config-${project_id}-${cluster_name}

Then just set kubeConfigPathPrefix and you're good to go.

Features

Secrets injection

TBD

Automatic documentation compilation

If documentation variable specified, pipilene will try to generate documentation with npm run docs command. Your nodejs script should be configured to generate index.html file to the ./docs-output directory.

Example:

...
"scripts": {
  "docs": "aglio -i docs/api.apib --theme-variables flatly -o docs-output/index.html"
},
...

Configuration options

  • documentation/bucketUrl for example gs://bucket-name.your.domain
  • documentation/storageClass for example regional
  • documentation/location for example europe-west3
  • documentation/pathPrefix for example project-name

Jenkinsfile options

🔻 /projectFriendlyName

This option must be set, typically it's a parent project name for all your micro services e.g. order-hammer so you can call api micro service as order-hammer-api.

🔻 /kubeConfigPathPrefix

path to the directory where you store Kubertnetes config files. This option must be set in case you are using automated kubeconfig name resolution mentioned in the previous part of this document.

🔻 /gcpDockerRegistryPrefix

This option must be set, follow the official Google documentation to get the right prefix.

🔻 /buildsToKeep

Optional. Set how many logs of pipeline jobs are stored on Jenkins master (applies to all branches). Default value is 30

🔻 /sshCredentialsId

This option must be set. It's the id of Jenkins credentials with the private RSA key for the interaction with private Git repositories. RSA key must be pre-processed this way:

sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g' my.key

🔻 /documentation

Optional. If set - it must be a Map with following keys:

  • pathPrefix subdirectory where yout want to put generated index.html file
  • bucketUrl url of your GCS bucker starting with gs://
  • gcpProjectId ID (not name!) of the GCP project where you want to create GCS bucket

🔻 /branchEnvs

This option must be set. It's always a Map, keys are named by Git branches.

🔻 /branchEnvs/[branch_name]/friendlyEnvName

This option must be set. It's typically production for the master branch, development for the development branch etc. It configures:

  • VAULTIER_ENVIRONMENT
  • it is part of Helm release name
  • general.environment Helm parameter

🔻 /branchEnvs/[branch_name]/gcpProjectId

This option must be set. It's the ID (not name!) of your GCP project.

🔻 /branchEnvs/[branch_name]/gkeClusterName

This option must be set. It's the name of Kubernetes cluster, you can get it dirrectly in the GCP console.

🔻 /branchEnvs/[branch_name]/k8sNamespace

This option must be set. Use default if you're using single GKE cluster for the single environment, otherwise you can for example use the same naming convention as for the friendlyEnvName naming.

🔻 /branchEnvs/[branch_name]/helmChart

This option must be set. It can be chart name (helm repository name) or path of the chart stored in the service's repository. Please note that repository is stored in ./repo subdirectory of the workplace so path must have repo/ prefix.

🔻 /branchEnvs/[branch_name]/helmValues

Optional. Values from this Map will be directly passed to the values.json so you can access them in the Helm chart in a standard fashion e.g. {{ .Values.deployment.replicaCount }}.

Please note that you should not use following keys in this context since they're automatically generated in the pipeline process: secrets, general.

🔻 /branchEnvs/[branch_name]/secretsInjection

Optional. Configure this key if you want to obtain secrets from the Hashicorp Vault. Content of this key must be a Map with following keys.

🔻 /branchEnvs/[branch_name]/secretsInjection/jenkinsCredentialsId

This option must be set if you want to obtain secrets from the Vault. It's the id of Jenkins credentials with the Vault token.

🔻 /branchEnvs/[branch_name]/secretsInjection/vaultUrl

This option must be set if you want to obtain secrets from the Vault. It should be the base url of your Vault instance.

🔻 /branchEnvs/[branch_name]/secretsInjection/secrets

This option must be set if you want to obtain secrets from the Vault. Content of this key must be a Map with following keys.

🔻 /branchEnvs/[branch_name]/secretsInjection/secrets/[]vaultSecretPath

This option must be set if you want to obtain secrets from the Vault. It's REST compatible path so it's compatible with KV1 or KV2.

🔻 /branchEnvs/[branch_name]/secretsInjection/secrets/[]keyMap This option must be set if you want to obtain secrets from the Vault. Content of this key must be a List with following Maps.

🔻 /branchEnvs/[branch_name]/secretsInjection/secrets/[]keyMap/[]vault This option must be set if you want to obtain secrets from the Vault. This key represents the remote key in the Vault document.

🔻 /branchEnvs/[branch_name]/secretsInjection/secrets/keyMap/[]local This option must be set if you want to obtain secrets from the Vault. This key represents the local key that you can use while accessing secrets in the Helm chart. It can be the same as the remote key but keep in mind that all secrets are put to the flat Map so local key should have unique name.

Jenkinsfile format

Simple example without secrets injection

PipelineNode{
  // app specific stuff
  projectFriendlyName = "your-awesome-project-name"
  appName = "api"
  appRole = "server"
  appTier = "backend"
  slackChannel = "#ci-channel011"
  logsToKeep = 30

  // RSA private key for ssh operations (git)
  sshCredentialsId = "jenkins-ssh-key"
  documentation = [:] // this won't trigger documentation stage

  // following properties can be passed to certain environments (below)
  envDefaults = [
    gcpDockerRegistryPrefix: "eu.gcr.io",
    kubeConfigPathPrefix: "/home/jenkins/.kube",
    helmChart: "repo/helm/chart/default",
    injectSecretsDeployment: true,
    injectSecretsTest: true,
    vaultAddr: "https://vault.co.uk"
    vaultTokenSecretId: "my-jenkins-secret",
    kubeConfigPathPrefix: "/home/jenkins/.kube",
    dryRun: false,
    debugMode: false,
    nodeTestEnv: [NODE_ENV: 'test', NODE_PATH: '.'],
    runLint: true,
    runNpmAudit: true,
    debugMode: false,
    logToBucket: true,
    logBucketUrl: "gs://api-logs",
    jenkinsCredentialsId: "jenkins-log-to-bucket"
  ]

  branchEnvs = [:]
  branchEnvs.development = [
    friendlyEnvName: "development",
    gcpProjectId: "gcp-project-id1234",
    gkeClusterName: "development",
    k8sNamespace: "default",
    helmValues: "repo/helm/values/development.yaml",
  ]

  branchEnvs.stage = [
    friendlyEnvName: "stage",
    gcpProjectId: "gcp-project-id1234",
    gkeClusterName: "stage",
    k8sNamespace: "default",
    helmValues: "repo/helm/values/stage.yaml",
  ]

  branchEnvs.master = [
    friendlyEnvName: "production",
    gcpProjectId: "gcp-project-id1234",
    gkeClusterName: "production",
    k8sNamespace: "default",
    helmValues: "repo/helm/values/production.yaml",
  ]
}

Dockerfile format

As you may have noticed - Jenkinsfile contains jenkins-ssh-key option. What is it for? Well sometimes you need to use private repositories during the npm install phase so this is the way how to do it. You just need to create a new Jenkins secret with the private RSA key and adjust your Dockerfile to perform multi-stage build. Here's the example:

# BUILDER IMAGE
FROM node:8.12.0 AS builder
ARG PRIVATE_KEY
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN mkdir ~/.ssh/
# PRIVATE_KEY=$(sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g' my.key)
RUN echo $PRIVATE_KEY > ~/.ssh/id_rsa
RUN chmod 0400 ~/.ssh/id_rsa
RUN eval `ssh-agent -s` && ssh-add ~/.ssh/id_rsa
RUN ssh-keyscan your.private.gitlab.domain.co.uk > /root/.ssh/known_hosts
# build command
RUN npm set unsafe-perm true
RUN npm install

# MAIN IMAGE
FROM node:8.12.0
ENV NODE_PATH=./config:./app
WORKDIR /usr/src/app
COPY --from=builder /usr/src/app /usr/src/app
EXPOSE 3000
CMD [ "npm", "start" ]

Future work

  • enhance processing of Jenkinsfile variables. Some sort of class wrapper would be nice

Credits

jenkins-pipeline-nodejs's People

Contributors

vranystepan avatar sandratatarevicova avatar tomashejatko avatar beranm14 avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.