Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support latest Docker Engine and Jenkins remoting image #28

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

## Why not Cloud API ?

Jenkins `hudson.slaves.Cloud` is designed to manage virtual machines, i.e. heavy to bootstrap, (relatively) long lived.
Jenkins `hudson.slaves.Cloud` is designed to manage virtual machines, i.e. heavy to bootstrap, (relatively) long lived.
As we manage containers, which are fast to start (as long as image is available on host) and designed to only host a single build,
the API doesn't strictly match our needs.

## Build Pod

The Jenkins slave is created as a set of containers, a.k.a. "pod", oen of them being used to establish the jenkins remoting
The Jenkins slave is created as a set of containers, a.k.a. "pod", oen of them being used to establish the jenkins remoting
communication channel, the others to run build steps, sharing volumes and network. This set of container is internally documented
as `com.cloudbees.jenkins.plugins.containerslaves.DockerBuildContext`.

Expand All @@ -20,15 +20,15 @@ As a workaround, we register a custom `hudson.model.queue.QueueListener` to be n
then can create the required containers without delay. It also assign a unique `hudson.model.Label`, to ensure this container
will only run once and assigned to this exact build.

## Container Provisioner
## Container Provisioner

`com.cloudbees.jenkins.plugins.containerslaves.DockerProvisioner` is responsible to create the build pob. For this purpose it
relies on a single, common, slave remoting image. `com.cloudbees.jenkins.plugins.containerslaves.DockerDriver` do handle the
relies on a single, common, slave remoting image. `com.cloudbees.jenkins.plugins.containerslaves.DockerDriver` do handle the
technical details

## Security

We arbitrary choose to launch command inside containers with UNIX user `jenkins` (uid 10000, gid 100) which is defined in the remoting container image.
We arbitrary choose to launch command inside containers with UNIX user `jenkins` (uid 1000, gid 1000) which is defined in the remoting container image.

To use this user in unknown containers images, we use `docker cp` to update `/etc/passwd` and `/etc/group` (so commands like `id -a ` work as expected).

Expand Down
8 changes: 4 additions & 4 deletions Docker.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Container-slaves Docker implementation

Plugin is relying on Docker for container management.
Plugin is relying on Docker for container management.

Remoting is established with a fixed image `jenkinsci/slave`.
Remoting is established with a fixed image `jenkinsci/slave`.
To prevent classes version mismatch, we use `docker cp` at startup to inject the remoting jar bundled with Jenkins into the
container.

`TMPDIR` and `java.io.tmpdir` are set to `/home/jenkins/.tmp` so every build file should be created within `/home/jenkins`.

`/home/jenkins` is set as VOLUME, so it can be reused for a subsequent build, or browsed after the build
`/home/jenkins` is set as VOLUME, so it can be reused for a subsequent build, or browsed after the build
as long as the container isn't removed.

Build commands are run inside arbitrary containers, ran as user `jenkins` (uid:10000, gid:10000) so there's no permission issue accessing the
Build commands are run inside arbitrary containers, ran as user `jenkins` (uid:1000, gid:1000) so there's no permission issue accessing the
workspace and other files inside `/home/jenkins`. This user is automatically created in container user do configure for the build.


Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/*
* The MIT License
*
*
* Copyright (c) 2015, CloudBees, Inc.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Expand Down Expand Up @@ -147,9 +147,10 @@ public Container launchRemotingContainer(TaskListener listener, String image, St
.add("--log-driver=none")

.add("--env", "TMPDIR="+ SLAVE_ROOT+".tmp")
.add("--user", "10000:10000")
.add("--user", "1000:1000")
.add("--rm")
.add("--volume", volume+":"+ SLAVE_ROOT)
.add("--ipc=shareable")
.add(image)
.add("java")
// set TMP directory within the /home/jenkins/ volume so it can be shared with other containers
Expand Down Expand Up @@ -190,7 +191,7 @@ public Container launchBuildContainer(TaskListener listener, String image, Conta
.add("--volumes-from", remotingContainer.getId())
.add("--net=container:" + remotingContainer.getId())
.add("--ipc=container:" + remotingContainer.getId())
.add("--user", "10000:10000");
.add("--user", "1000:1000");

applyHints(hints, args);

Expand Down Expand Up @@ -240,14 +241,14 @@ private void applyHints(List<Hint> hints, ArgumentListBuilder args) {
protected void injectJenkinsUnixGroup(Launcher launcher, String containerId) throws IOException, InterruptedException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
getFileContent(launcher, containerId, "/etc/group", out);
out.write("jenkins:x:10000:\n".getBytes(StandardCharsets.UTF_8));
out.write("jenkins:x:1000:\n".getBytes(StandardCharsets.UTF_8));
putFileContent(launcher, containerId, "/etc", "group", out.toByteArray());
}

protected void injectJenkinsUnixUser(Launcher launcher, String containerId) throws IOException, InterruptedException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
getFileContent(launcher, containerId, "/etc/passwd", out);
out.write("jenkins:x:10000:10000::/home/jenkins:/bin/false\n".getBytes(StandardCharsets.UTF_8));
out.write("jenkins:x:1000:1000::/home/jenkins:/bin/false\n".getBytes(StandardCharsets.UTF_8));
putFileContent(launcher, containerId, "/etc", "passwd", out.toByteArray());
}

Expand Down