Created
February 15, 2017 08:37
-
-
Save Gorniv/3ea896c89ea944f702feac5c2c8a6bf8 to your computer and use it in GitHub Desktop.
Пример jenkins в контейнере для сборки докер образов + Jenkinsfile по которому идет сборка
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
version: "2" | |
services: | |
jenkins: | |
build: ./jenkins | |
volumes: | |
- /var/jenkins_home:/var/jenkins_home | |
- /var/run/docker.sock:/var/run/docker.sock | |
environment: | |
JAVA_OPTS: "-Dhudson.model.DirectoryBrowserSupport.CSP=\"default-src *;style-src 'unsafe-inline';script-src 'unsafe-inline';img-src * data: blob: filesystem:\"" | |
restart: always |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM jenkins | |
USER root | |
RUN apt-get update \ | |
&& apt-get install -y ruby python make openssl ca-certificates gcc g++\ | |
&& gem install sass | |
# Install docker cli | |
RUN curl -o docker.tgz https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz \ | |
&& tar -xvzf docker.tgz \ | |
&& mv docker/docker /usr/bin/docker && chmod +x /usr/bin/docker \ | |
&& rm -rf docker.tgz docker | |
#This allows jenkins access to /var/run/docker.sock | |
RUN groupadd -g 999 hostroot | |
RUN adduser jenkins hostroot | |
#Install docker-compose | |
RUN curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose \ | |
&& chmod +x /usr/local/bin/docker-compose | |
#Install docker-machine | |
RUN curl -L https://github.com/docker/machine/releases/download/v0.8.1/docker-machine-`uname -s`-`uname -m` > /usr/local/bin/docker-machine && \ | |
chmod +x /usr/local/bin/docker-machine | |
# Replace shell with bash so we can source files | |
RUN rm /bin/sh && ln -s /bin/bash /bin/sh | |
ENV NVM_DIR /usr/local/nvm | |
ENV NODE_VERSION 5.12.0 | |
# Install nvm with node and npm | |
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.4/install.sh | bash \ | |
&& source $NVM_DIR/nvm.sh \ | |
&& nvm install $NODE_VERSION \ | |
&& nvm alias default $NODE_VERSION \ | |
&& nvm use default | |
ENV NODE_PATH $NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules | |
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH | |
USER jenkins |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!groovy | |
def project = 'projectname' | |
properties properties: [pipelineTriggers([]), [$class: 'GithubProjectProperty', displayName: 'Jenkins', projectUrlStr: "https://github.com/organizationname/${project}/"]] | |
env.NODE_ENV = "testing" | |
env.DOCKER_IMAGE = "${project}" | |
env.DOCKER_IMAGE_TAG = "${env.BRANCH_NAME}b${env.BUILD_NUMBER}" | |
env.PROJECT_NAME = "${project}${env.BRANCH_NAME}b${env.BUILD_NUMBER}" | |
env.PROJECT_NAME = env.PROJECT_NAME.replaceAll(~/[^\d\w]/,'').toLowerCase() | |
env.NUM_OF_WORKERS = 1 | |
env.SLACK_CHAT = "#${project}" | |
print "Environment will be : ${env.NODE_ENV}" | |
print "Image name will be : ${env.DOCKER_IMAGE}" | |
print "Docker compose project name will be : ${env.PROJECT_NAME}" | |
node { | |
step([$class: 'GitHubCommitStatusSetter']) | |
def error | |
def image | |
def imageStatic | |
try { | |
stage('Checkout') { | |
checkout scm | |
} | |
stage('Check configs') { | |
testComposeConfigs "staging" | |
testComposeConfigs "production" | |
testComposeConfigs "testing" | |
testComposeConfigs "local" | |
} | |
stage('Build') { | |
sh 'node -v' | |
sh 'cd ./client && npm prune && npm install' | |
sh 'npm prune && npm install' | |
sh 'cp tests/config.jenkins.js ./config.js' | |
sh 'npm run build' | |
} | |
stage('Build Docker Image'){ | |
parallel 'image': { | |
image = docker.build("${env.DOCKER_IMAGE}:${env.DOCKER_IMAGE_TAG}") | |
}, 'image-static': { | |
if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'production') { | |
imageStatic = docker.build("${env.DOCKER_IMAGE}-static:${env.DOCKER_IMAGE_TAG}", '-f ./client/Dockerfile .') | |
} | |
} | |
} | |
stage('Start services') { | |
env.WORKSPACE = sh(returnStdout: true, script: 'pwd').trim() | |
compose "up -d" | |
compose "scale selenium-chrome=${env.NUM_OF_WORKERS}" | |
sleep 5 | |
compose "exec -T mongodb mongo --eval 'rs.initiate()'" | |
compose "exec -T app mkdir -p tests/out" | |
env.SELENIUM = compose('port selenium 4444').trim().replace(/0.0.0.0:/,'') | |
env.MONGODB = compose('port mongodb 27017').trim().replace(/0.0.0.0/,'server.organizationname.com') | |
env.APP_API = compose('port app 3000').trim().replace(/0.0.0.0/,'http://server.organizationname.com') | |
env.MAILDEV_WEB = compose('port maildev 80').trim().replace(/0.0.0.0:/,'') | |
env.MAILDEV_SMTP = compose('port maildev 25').trim().replace(/0.0.0.0:/,'') | |
env.MAILDEV_HOST = 'ci.organizationname.com' | |
} | |
stage('Test') { | |
sh 'rm -rf ./tests/out && mkdir -p ./tests/out/reports' | |
parallel 'eslint':{ | |
sh 'npm run eslint' | |
}, 'unittest':{ | |
sh "npm run unittest" | |
}, 'karma':{ | |
sh "npm run karma" | |
}, 'selenium': { | |
sh "node --harmony node_modules/.bin/parallel-cucumber-js -r tests/bootstrap.js -r tests/features -w ${env.NUM_OF_WORKERS} -f json:./tests/out/output.json tests/features" | |
} | |
} | |
if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'production') { | |
def tag | |
//todo: fix server name | |
if (env.BRANCH_NAME == 'master'){ | |
tag = 'staging' | |
env.DEPLOY_SERVER = 'docker' | |
} else { | |
tag = 'production' | |
env.DEPLOY_SERVER = 'docker' | |
} | |
//this prevents parallel deploy | |
lock("deploy:${project}:${tag}") { | |
stage ('Push Docker Images') { | |
docker.withRegistry('https://registry.organizationname.com/v2/', 'docker-registry') { | |
parallel 'tag': { | |
image.push(tag) | |
}, 'tag-static': { | |
imageStatic.push(tag) | |
} | |
} | |
} | |
stage("Deploy to ${tag}") { | |
remoteDocker "docker-compose -f docker/${tag}.yaml -p ${project}_${tag} ps" | |
remoteDocker "docker-compose -f docker/${tag}.yaml -p ${project}_${tag} pull app backend" | |
remoteDocker "docker-compose -f docker/${tag}.yaml -p ${project}_${tag} restart consul" | |
remoteDocker "docker-compose -f docker/${tag}.yaml -p ${project}_${tag} up -d --remove-orphans" | |
remoteDocker "docker-compose -f docker/${tag}.yaml -p ${project}_${tag} restart app" | |
remoteDocker "docker-compose -f docker/${tag}.yaml -p ${project}_${tag} ps" | |
} | |
} | |
} | |
currentBuild.result = "SUCCESS" | |
step([$class: 'GitHubCommitStatusSetter']) | |
} catch (err) { | |
currentBuild.result = "FAILURE" | |
print err | |
error = err | |
} | |
stage('Cleanup') { | |
if (currentBuild.result == "FAILURE") { | |
step([$class: 'GitHubCommitStatusSetter']) | |
slackSend channel: env.SLACK_CHAT, color: "danger", message: "${currentBuild.result}: Build <${env.BUILD_URL}|${env.BUILD_DISPLAY_NAME}> <${env.CHANGE_URL}|${env.CHANGE_TITLE}> by ${env.CHANGE_AUTHOR} (${env.CHANGE_TARGET}) with error: ${error}" | |
} | |
try { | |
stopAndRemove() | |
} catch (err) { | |
print "${err}" | |
slackSend channel: '#ci', color: "danger", message: "Build <${env.BUILD_URL}|${env.BUILD_DISPLAY_NAME}> ${err}" | |
} | |
} | |
} | |
def stopAndRemove(){ | |
try { | |
copyTestOut() | |
} catch (err) { | |
print "${err}" | |
slackSend channel: '#ci', color: "danger", message: "Build <${env.BUILD_URL}|${env.BUILD_DISPLAY_NAME}> ${err}" | |
} | |
compose("stop") | |
compose("rm -fv") | |
sh "docker network rm \$(docker network ls -q -f 'name=${env.PROJECT_NAME}')" | |
try { | |
sh "docker images --format '{{.ID}} {{.Repository}} {{.Tag}}' | grep ${env.DOCKER_IMAGE_TAG} | cut -d ' ' -f 1 | xargs -n 1 docker rmi -f" | |
} catch(err) { | |
print "${err}" | |
slackSend channel: '#ci', color: "danger", message: "Build <${env.BUILD_URL}|${env.BUILD_DISPLAY_NAME}> ${err}" | |
} | |
} | |
def compose(command){ | |
return sh(returnStdout: true, script:"docker-compose -f docker/testing.yaml -p ${env.PROJECT_NAME} ${command}") | |
} | |
def testComposeConfigs(config) { | |
return sh(returnStdout: true, script:"docker-compose -f docker/${config}.yaml config -q") | |
} | |
def remoteDocker(command){ | |
sh "eval \$(docker-machine env ${env.DEPLOY_SERVER} --shell bash) && ${command}" | |
} | |
def copyTestOut(){ | |
try { | |
sh 'node tests/html-report.js' | |
publishHTML(target: [allowMissing: false, alwaysLinkToLastBuild: true, keepAll: false, reportDir: 'tests/out/reports', reportFiles: 'report.html', reportName: 'Selenium Report']) | |
} catch (err) { | |
print "${err}" | |
slackSend channel: '#ci', color: "danger", message: "Build <${env.BUILD_URL}|${env.BUILD_DISPLAY_NAME}> ${err}" | |
} | |
sh 'mkdir -p tests/out/logs' | |
compose("config --services | xargs -I {} -t bash -c 'docker-compose -f docker/testing.yaml -p ${env.PROJECT_NAME} logs --no-color {} > tests/out/logs/{}.log'") | |
archiveArtifacts artifacts: 'tests/out/**/*.*', excludes: null | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment