This is the third day of my participation in the More text Challenge. For details, see:More article challenges
This article documented how to use Jenkins Pipeline for build and remote deployment.
Automated process
A common project automation process in the enterprise would be for a build machine to pull code from a repository and build it. When the build is complete, the product is pushed to a repository, such as a mirror repository, with a test environment in between for automated or manual testing, and finally remote deployment.
The project structure
Here we use the Go project structure, which looks something like this:
|-- my-app
|-- .gitignore
|-- README.md
|-- LICENSE
|-- go.mod
|-- go.sum
|-- main.go
|-- pkg
|-- ...
Copy the code
The project build
Since we are building a Go project, if we use a private library, Git credentials will be required in Go Mod Tidy. We can create a Username with Password credential in Jenkins’ credential management. Username is the Username of GitHub, and password is the AccessToken of GitHub. The main use here is the AccessToken, but Username is not needed.
But using usernamePassword in Jenkins Pipeline requires defining both usernameVariable and passwordVariable.
stage('Build') {
steps {
withCredentials(bindings: [
usernamePassword(credentialsId: 'GITHUB_CREDENTIAL'.usernameVariable: 'GITHUB_USER'.passwordVariable: 'GITHUB_ACCESS_TOKEN'
)
]) {
sh ''' git config --global url."https://${GITHUB_ACCESS_TOKEN}:[email protected]/".insteadOf "https://github.com/" go mod tidy go build -o bin/my-app main.go '''}}}Copy the code
Remote deployment
After the build is complete, we push the build artifacts to the artifact repository, and then we can pull the build artifacts from the artifact repository to deploy the test environment and test them. After verification, the verified artifacts are pulled from the artifact repository and deployed online.
But in this article, our application is relatively simple, and we can ignore the push to the artifact library and the in-between testing and verification, with the goal of deploying immediately after build.
Typically, the online environment and the build environment are not on the same machine, so at this point we need to copy the build artifacts to another server and then deploy them on another server.
Since we need to operate on another server, we need to configure the three credentials of DEPLOY_HOST, DEPLOY_PORT and SSH_CREDENTIAL on Jenkins. In the command, DEPLOY_HOST and DEPLOY_PORT are the credentials of Secret TEXT type, and SSH_CREDENTIAL is the credentials of SSH Username with Private Key type.
stage('Deploy') {
environment {
DEPLOY_HOST = credentials('DEPLOY_HOST')
DEPLOY_PORT = credentials('DEPLOY_PORT')
}
steps {
withCredentials([
sshUserPrivateKey(credentialsId: 'SSH_CREDENTIAL'.keyFileVariable: 'SSH_KEY'.usernameVariable: 'SSH_USERNAME'),
]) {
sh """ mkdir -p ~/.ssh && chmod 700 ~/.ssh echo 'StrictHostKeyChecking no' >> /etc/ssh/ssh_config cat ${SSH_KEY} > ~/.ssh/id_rsa && chmod 400 ~/.ssh/id_rsa scp -P ${DEPLOY_PORT} bin/my-app ${SSH_USER}@${DEPLOY_HOST}:/data/my-app ssh -p ${DEPLOY_PORT} ${SSH_USER}@${DEPLOY_HOST} \"nohup /data/my-app >> /data/my-app.log 2>&1 &\" """}}}Copy the code
The deployment steps include:
- Copy the build artifacts to the deployment server
- Execute deployment commands on the deployment server, such as
nohup /data/my-app >> /data/my-app.log 2>&1 &
It simplifies some details, such as the need to back up data before deployment. So here we can write a complex deployment script deploy.sh to put in the project, and then copy the deployment script file to the deployment server using SCP in Jenkins Pipeline, assuming in /data/deploy.sh, SSH -p ${DEPLOY_PORT} ${SSH_USER}@${DEPLOY_HOST} /bin/bash /data/deploy.sh
Complete Jenkins Pipeline
pipeline {
agent {
docker {
image '1.15 alpine golang:'
args '-v /data/my-app-cache:/go/.cache'
}
}
options {
timeout(time: 20.unit: 'MINUTES')
disableConcurrentBuilds()
}
stages {
stage('Build') {
steps {
withCredentials(bindings: [
usernamePassword(credentialsId: 'GITHUB_CREDENTIAL'.usernameVariable: 'GITHUB_USER'.passwordVariable: 'GITHUB_ACCESS_TOKEN'
)
]) {
sh ''' git config --global url."https://${GITHUB_ACCESS_TOKEN}:[email protected]/".insteadOf "https://github.com/" go mod tidy go build -o bin/my-app main.go '''
}
}
}
stage('Deploy') {
environment {
DEPLOY_HOST = credentials('DEPLOY_HOST')
DEPLOY_PORT = credentials('DEPLOY_PORT')
}
steps {
withCredentials([
sshUserPrivateKey(credentialsId: 'SSH_CREDENTIAL'.keyFileVariable: 'SSH_KEY'.usernameVariable: 'SSH_USERNAME'),
]) {
sh """ mkdir -p ~/.ssh && chmod 700 ~/.ssh echo 'StrictHostKeyChecking no' >> /etc/ssh/ssh_config cat ${SSH_KEY} > ~/.ssh/id_rsa && chmod 400 ~/.ssh/id_rsa scp -P ${DEPLOY_PORT} bin/my-app ${SSH_USER}@${DEPLOY_HOST}:/data/my-app ssh -p ${DEPLOY_PORT} ${SSH_USER}@${DEPLOY_HOST} \"nohup /data/my-app >> /data/my-app.log 2>&1 &\" """
}
}
}
}
}
Copy the code
Thank you for reading
The author is not only, very welcome to the content of this article to correct, or discuss with the author!
Personal blog
K8scat.com/posts/remot…