提交 8c83a03a 编写于 作者: P Piotr Bryk 提交者: GitHub

Build and push HEAD image on every build on master (#1377)

* Adjust travis to push canary image on successful build

* Build and push HEAD image on every build on master

Also rename canary to head for images that we build. This name conveys
better what we actually do.

* Remove Google SDK reference from the travis config
上级 da1f2c61
......@@ -20,6 +20,7 @@
# According to the documentation: http://docs.travis-ci.com/user/docker/
# sudo is required to enable docker in Travis CI.
sudo: true
# Cache downloaded Node.JS modules & Bower frontend dependencies for faster builds.
cache:
directories:
......@@ -52,5 +53,6 @@ before_script:
- docker --version
script: ./node_modules/.bin/gulp check:local-cluster --heapsterServerHost 'http://localhost:8082'
script: ./node_modules/.bin/gulp ci --heapsterServerHost 'http://localhost:8082'
after_script: ./node_modules/.bin/gulp coverage-codecov-upload
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Entrypoint tasks for ci environments.
*/
import childProcess from 'child_process';
import gulp from 'gulp';
/**
* Entry point task for CI environments.
*/
gulp.task('ci', ['check:local-cluster'], (doneFn) => {
if (process.env.TRAVIS) {
// Pushe head images when docker user and password are available.
if (process.env.TRAVIS_PULL_REQUEST === 'false' && process.env.DOCKER_USER &&
process.env.DOCKER_PASS) {
childProcess.exec('docker login -u $DOCKER_USER -p $DOCKER_PASS', (err, stdout, stderr) => {
if (err) {
doneFn(new Error(`Cannot login to docker: ${err}, ${stdout}, ${stderr}`));
} else {
gulp.start('push-to-docker:head:cross');
doneFn();
}
});
} else {
doneFn();
}
} else {
doneFn(new Error('Not in a CI environment (such as Travis). Aborting.'));
}
});
......@@ -43,6 +43,15 @@ const arch = {
list: ['amd64', 'arm', 'arm64', 'ppc64le'],
};
/**
* Configuration for container registry to push images to.
*/
const containerRegistry = {
release: 'gcr.io/google_containers',
/** Default to a environment variable */
head: process.env.DOCKER_HUB_PREFIX || 'kubernetes',
};
/**
* Package version information.
*/
......@@ -52,20 +61,25 @@ const version = {
*/
release: 'v1.4.1',
/**
* Version name of the canary release of the project.
* Version name of the head release of the project.
*/
canary: 'canary',
head: 'head',
};
/**
* Base name for the docker image.
*/
const imageNameBase = 'gcr.io/google_containers/kubernetes-dashboard';
const imageNameBase = 'kubernetes-dashboard';
/**
* Exported configuration object with common constants used in build pipeline.
*/
export default {
/**
* Configuration for container registry to push images to.
*/
containerRegistry: containerRegistry,
/**
* Backend application constants.
*/
......@@ -116,24 +130,32 @@ export default {
version: version,
/**
* Image name for the canary release for current architecture.
* Image name base for current architecture.
*/
imageNameBase: `${imageNameBase}-${arch.default}`,
/**
* Image name for the head release for current architecture.
*/
canaryImageName: `${imageNameBase}-${arch.default}:${version.canary}`,
headImageName: `${containerRegistry.head}/${imageNameBase}-${arch.default}:${version.head}`,
/**
* Image name for the versioned release for current architecture.
*/
releaseImageName: `${imageNameBase}-${arch.default}:${version.release}`,
releaseImageName:
`${containerRegistry.release}/${imageNameBase}-${arch.default}:${version.release}`,
/**
* Image name for the canary release for all supported architecture.
* Image name for the head release for all supported architecture.
*/
canaryImageNames: arch.list.map((arch) => `${imageNameBase}-${arch}:${version.canary}`),
headImageNames: arch.list.map(
(arch) => `${containerRegistry.head}/${imageNameBase}-${arch}:${version.head}`),
/**
* Image name for the versioned release for all supported architecture.
*/
releaseImageNames: arch.list.map((arch) => `${imageNameBase}-${arch}:${version.release}`),
releaseImageNames: arch.list.map(
(arch) => `${containerRegistry.release}/${imageNameBase}-${arch}:${version.release}`),
},
/**
......
......@@ -24,83 +24,106 @@ import conf from './conf';
import {multiDest} from './multidest';
/**
* @param {!Array<string>} args
* @param {function(?Error=)} doneFn
*/
function spawnDockerProcess(args, doneFn) {
let dockerTask = child.spawn('docker', args, {stdio: 'inherit'});
// Call Gulp callback on task exit. This has to be done to make Gulp dependency management
// work.
dockerTask.on('exit', function(code) {
if (code === 0) {
doneFn();
} else {
doneFn(new Error(`Docker command error, code: ${code}`));
}
});
}
/**
* Creates canary Docker image for the application for current architecture.
* The image is tagged with the image name configuration constant.
*/
gulp.task('docker-image:canary', ['build', 'docker-file'], function(doneFn) {
buildDockerImage([[conf.deploy.canaryImageName, conf.paths.dist]], doneFn);
});
/**
* Creates release Docker image for the application for current architecture.
* Creates head Docker image for the application for current architecture.
* The image is tagged with the image name configuration constant.
*/
gulp.task('docker-image:release', ['build', 'docker-file'], function(doneFn) {
buildDockerImage([[conf.deploy.releaseImageName, conf.paths.dist]], doneFn);
gulp.task('docker-image:head', ['build', 'docker-file'], function() {
return buildDockerImage([[conf.deploy.headImageName, conf.paths.dist]]);
});
/**
* Creates canary Docker image for the application for all architectures.
* Creates head Docker image for the application for all architectures.
* The image is tagged with the image name configuration constant.
*/
gulp.task('docker-image:canary:cross', ['build:cross', 'docker-file:cross'], function(doneFn) {
buildDockerImage(lodash.zip(conf.deploy.canaryImageNames, conf.paths.distCross), doneFn);
gulp.task('docker-image:head:cross', ['build:cross', 'docker-file:cross'], function() {
return buildDockerImage(lodash.zip(conf.deploy.headImageNames, conf.paths.distCross));
});
/**
* Creates release Docker image for the application for all architectures.
* The image is tagged with the image name configuration constant.
*/
gulp.task('docker-image:release:cross', ['build:cross', 'docker-file:cross'], function(doneFn) {
buildDockerImage(lodash.zip(conf.deploy.releaseImageNames, conf.paths.distCross), doneFn);
gulp.task('docker-image:release:cross', ['build:cross', 'docker-file:cross'], function() {
return buildDockerImage(lodash.zip(conf.deploy.releaseImageNames, conf.paths.distCross));
});
/**
* Pushes cross-compiled canary images to GCR.
* Pushes cross compiled head images to Docker Hub.
*/
gulp.task('push-to-gcr:canary', ['docker-image:canary:cross'], function(doneFn) {
pushToGcr(conf.deploy.versionCanary, doneFn);
gulp.task('push-to-docker:head:cross', ['docker-image:head:cross'], function() {
// If travis commit is available push all images and their copies tagged with commit SHA.
if (process.env.TRAVIS_COMMIT) {
let allImages = conf.deploy.headImageNames.concat([]);
let spawnPromises = conf.deploy.headImageNames.map((imageName) => {
// Regex to extract base image and its tag.
let extractBaseRegex = /(.*):(\w+)/i;
let newImageName = `${imageName.match(extractBaseRegex)[1]}:${process.env.TRAVIS_COMMIT}`;
allImages.push(newImageName);
return new Promise((resolve, reject) => {
spawnDockerProcess(
[
'tag',
imageName,
newImageName,
],
(err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
});
return Promise.all(spawnPromises).then(() => {
return pushToDocker(allImages);
});
} else {
return pushToDocker(conf.deploy.headImageNames);
}
});
/**
* Pushes cross-compiled release images to GCR.
*/
gulp.task('push-to-gcr:release', ['docker-image:release:cross'], function(doneFn) {
pushToGcr(conf.deploy.versionRelease, doneFn);
gulp.task('push-to-gcr:release:cross', ['docker-image:release:cross'], function() {
return pushToGcr(conf.deploy.releaseImageNames);
});
/**
* Processes the Docker file and places it in the dist folder for building.
*/
gulp.task('docker-file', ['clean-dist'], function() {
dockerFile(conf.paths.dist);
return dockerFile(conf.paths.dist);
});
/**
* Processes the Docker file and places it in the dist folder for all architectures.
*/
gulp.task('docker-file:cross', ['clean-dist'], function() {
dockerFile(conf.paths.distCross);
return dockerFile(conf.paths.distCross);
});
/**
* @param {!Array<string>} args
* @param {function(?Error=)} doneFn
*/
function spawnDockerProcess(args, doneFn) {
let dockerTask = child.spawn('docker', args, {stdio: 'inherit'});
// Call Gulp callback on task exit. This has to be done to make Gulp dependency management
// work.
dockerTask.on('exit', function(code) {
if (code === 0) {
doneFn();
} else {
doneFn(new Error(`Docker command error, code: ${code}`));
}
});
}
/**
* @param {!Array<!Array<string>>} imageNamesAndDirs (image name, directory) pairs
* @return {!Promise}
......@@ -132,27 +155,80 @@ function buildDockerImage(imageNamesAndDirs) {
}
/**
* @param {string} version
* @param {function(?Error=)} doneFn
* @param {!Array<string>} imageNames
* @return {!Promise}
*/
function pushToGcr(version, doneFn) {
let imageUri = `${conf.deploy.imageName}:${version}`;
function pushToDocker(imageNames) {
let spawnPromises = imageNames.map((imageName) => {
return new Promise((resolve, reject) => {
spawnDockerProcess(
[
'push',
imageName,
],
(err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
});
let childTask = child.spawn('gcloud', ['docker', 'push', imageUri], {stdio: 'inherit'});
return Promise.all(spawnPromises);
}
childTask.on('exit', function(code) {
/**
* @param {!Array<string>} args
* @param {function(?Error=)} doneFn
*/
function spawnGCloudProcess(args, doneFn) {
let gcloudTask = child.spawn('gcloud', args, {stdio: 'inherit'});
// Call Gulp callback on task exit. This has to be done to make Gulp dependency management
// work.
gcloudTask.on('exit', function(code) {
if (code === 0) {
doneFn();
} else {
doneFn(new Error(`gcloud command error, code: ${code}`));
doneFn(new Error(`GCloud command error, code: ${code}`));
}
});
}
/**
* @param {!Array<string>} imageNames
* @return {!Promise}
*/
function pushToGcr(imageNames) {
let spawnPromises = imageNames.forEach((imageName) => {
return new Promise((resolve, reject) => {
spawnGCloudProcess(
[
'docker',
'push',
imageName,
],
(err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
});
return Promise.all(spawnPromises);
}
/**
* @param {string|!Array<string>} outputDirs
* @param {function(?Error=)} doneFn
* @return {stream}
*/
function dockerFile(outputDirs) {
return gulp.src(path.join(conf.paths.deploySrc, 'Dockerfile')).pipe(multiDest(outputDirs));
function dockerFile(outputDirs, doneFn) {
return gulp.src(path.join(conf.paths.deploySrc, 'Dockerfile'))
.pipe(multiDest(outputDirs, doneFn));
}
......@@ -20,6 +20,7 @@
*/
import './build/check';
import './build/cluster';
import './build/ci';
import './build/backend';
import './build/build';
import './build/dependencies';
......
......@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# Configuration to deploy canary version of the Dashboard UI.
# Configuration to deploy head version of the Dashboard UI.
#
# Example usage: kubectl create -f <this_file>
......@@ -23,24 +23,21 @@ items:
apiVersion: v1
metadata:
labels:
app: kubernetes-dashboard-canary
version: canary
name: kubernetes-dashboard-canary
app: kubernetes-dashboard-head
name: kubernetes-dashboard-head
namespace: kube-system
spec:
replicas: 1
selector:
app: kubernetes-dashboard-canary
version: canary
app: kubernetes-dashboard-head
template:
metadata:
labels:
app: kubernetes-dashboard-canary
version: canary
app: kubernetes-dashboard-head
spec:
containers:
- name: kubernetes-dashboard-canary
image: gcr.io/google_containers/kubernetes-dashboard-amd64:canary
- name: kubernetes-dashboard-head
image: gcr.io/google_containers/kubernetes-dashboard-amd64:head
imagePullPolicy: Always
ports:
- containerPort: 9090
......@@ -60,8 +57,8 @@ items:
apiVersion: v1
metadata:
labels:
app: kubernetes-dashboard-canary
name: dashboard-canary
app: kubernetes-dashboard-head
name: dashboard-head
namespace: kube-system
spec:
type: NodePort
......@@ -69,4 +66,4 @@ items:
- port: 80
targetPort: 9090
selector:
app: kubernetes-dashboard-canary
app: kubernetes-dashboard-head
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册