An experimental Windows builder for Cloud Build.
Grant Compute Engine permissions to your Cloud Build service account:
gcloud services enable compute.googleapis.com export PROJECT=$(gcloud info --format='value(config.project)') export MEMBER=$(gcloud projects describe $PROJECT --format 'value(projectNumber)')@cloudbuild.gserviceaccount.com gcloud projects add-iam-policy-binding $PROJECT --member=serviceAccount:$MEMBER --role='roles/compute.admin' gcloud projects add-iam-policy-binding $PROJECT --member=serviceAccount:$MEMBER --role='roles/iam.serviceAccountUser'
Clone this repository and build the builder:
gcloud builds submit --config=builder/cloudbuild.yaml builder/
Then, refer to the builder in your project's
cloudbuild.yaml. To spin up an ephemeral
n1-standard-1 VM on Compute Engine, simply provide the command you wish to execute. Your Cloud Build workspace is synchronized to
C:\workspace at server startup.
steps: - name: 'gcr.io/$PROJECT_ID/windows-builder' args: [ '--command', '<command goes here>' ]
To use a custom Windows image, specify the image URL using the
steps: - name: 'gcr.io/$PROJECT_ID/windows-builder' args: [ '--command', '<command goes here>' '--image', 'projects/$PROJECT_ID/global/images/my-windows-image']
The VM is configured by the builder and then deleted automatically at the end of the build. Command is executed by
cmd.exe; in most cases it will be a build script.
To use an existing Windows server instead, also provide the hostname, username and password:
steps: - name: 'gcr.io/$PROJECT_ID/windows-builder' args: [ '--hostname', 'host.domain.net', '--username', 'myuser', '--password', 's3cret', '--command', '<command goes here>' ]
Your server must support Basic Authentication (username and password) and your network must allow access from the internet on TCP port 5986. Do not submit plaintext passwords in your build configuration: instead, use encrypted credentials secured with Cloud KMS. In addition, you must clear up your workspace directory after use, and take care to manage concurrent builds.
Several example builds are provided:
- images/example prints "Hello World!" from Windows
- images/go-windows builds a Windows Go builder container image
- images/go-example builds a very simple Go application into a deployable Windows container. This relies on the Windows Go builder from the step above.
- images/docker-windows builds a Windows container with a Docker executable inside - useful for building containers within a Docker context itself.
Starting an ephemeral VM on Compute Engine takes about 3 min 31 sec, broken down as follows:
|Create new Compute Engine instance||7 sec||7 sec||3%|
|Wait for password reset||37 sec||45 sec||21%|
|Wait for Windows to finish booting||2 min 39 sec||3 min 24 sec||76%|
Frequent builds will benefit from creating a persistent Windows VM. To do this, see
Downloading and expanding archives is a common build step. While Powershell offers functionality to do this (the
Expand-Archive cmdlet) there are known performance issues. See PowerShell Archive issue #32.
windows-builder communicates with the remote server using WinRM over HTTPS. Basic authentication using username and password is currently supported.
For ephemeral VMs on Compute Engine, the initial password reset is performed using public key cryptography. The cleartext password is never sent over an unencrypted connection, and is stored in memory for the duration of the build.
The latest version of Windows Server 1803 DC Core for Containers (patched 2018-08-02) is currently used.
Windows supports two different types of containers: "Windows Server containers", similar to the traditional Linux container, and "Hyper-V containers", which rely on Virtual Machines. This code uses Windows Server containers, and as a result both the major and minor version of Windows must match between container and host.
The package manager in Windows Server 1803 provides Docker 17.06. However to run a Docker executable inside a Docker container as Cloud Build typically does, version 17.09 or higher is required to bind-mount the named pipe: see this pull request. e.g.,
docker run -v '\.\pipe\docker_engine:\.\pipe\docker_engine' ...
To debug issues with WinRM, Python users may find the PyWinRM package helpful, for example:
from winrm.protocol import Protocol p = Protocol( endpoint='https://<ip address>:5986/wsman', username=<username>, password=<password>, server_cert_validation='ignore') shell_id = p.open_shell() command_id = p.run_command(shell_id, 'ipconfig', ['/all']) std_out, std_err, status_code = p.get_command_output(shell_id, command_id) p.cleanup_command(shell_id, command_id) p.close_shell(shell_id)