K8s: Deploying a SPA
• Mark Eschbach
They say you need to do something several hundred times before you are an expert. This time I’ll be deploying a SPA using nginx with static content. Eventually I would love to check these out from an existing repository; eventually I will get there.
This is for a fresh project. So I’ll walk through the whole process, or at least until I get distracted.
Content Skelton
I suppose I need someting to dpeloy. I’ll just use the base react generator.
$ create-react-app maurice-dashboard
Not exactly delivering any value yet beyond the build system interface. Time to setup the Jenkins Pipeline to build a simple container.
pipeline {
agent any
stages {
stage('Unit tests in a docker container'){
agent {
docker { image 'node:13.12.0' }
}
steps {
sh 'yarn install'
sh 'yarn test --watchAll=false'
}
}
stage('Build Docker container'){
steps {
sh "docker build . -f ./.cd/Dockerfile --tag docker.artifacts.internal/maurice-dashboard:${env.BUILD_NUMBER}"
}
}
stage('Publish') {
steps {
sh "docker push docker.artifacts.internal/maurice-dashboard:${env.BUILD_NUMBER}"
}
}
stage('Deploy'){
steps {
sh ".cd/deploy.sh"
}
}
}
post {
success {
slackSend (color: '#00FF00', message: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
}
failure {
slackSend (color: '#FF0000', message: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
sh "docker rmi docker.artifacts.internal/maurice-dashboard:${env.BUILD_NUMBER}"
}
}
}
I do not like the drift in the Dockerfile
versus int eh Jenkinsfile
pipeline for testing, however at this time I do
not have a good solution to use the same file. The Dockerfile
for producing the SPA static content is below.
FROM node:13.12.0 AS builder
WORKDIR /app
COPY . /app
RUN chown -R node:node /app
USER node
ENV NODE_ENV production
RUN yarn install --production
RUN yarn build
FROM nginx:1.17.9
EXPOSE 80
COPY --from=builder /app/build /usr/share/nginx/html
COPY .cd/k8s-nginx.conf /etc/nginx/conf.d/default.conf
My current nginx.conf
file is pretty simple:
server {
listen 80;
access_log off;
error_log off;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
}
}
The deploy.sh
file is really a placeholder for pushing changes into the Kubernetes clusters in the future. For now it
just updates the integration environment via Helm.
#!/bin/bash
helm update --namespace maurice dashboard --set tag=${env.BUILD_NUMBER} -f integ.yaml
The integ.yaml
file contains environment specific setup. In this case it is just setting the imagePullSecret
. For
future implementations this may provide additional overrides or details.