Skip to content

Add support for remote DOCKER_HOST #270

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

Closed
wants to merge 5 commits into from
Closed
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
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,23 @@ It is important that the host of your private repositories has already been adde
`$HOME/.ssh/known_hosts` file, as the install process will fail otherwise due to host authenticity
failure.

### Remote docker hosts

If you have DOCKER_HOST set to a remote mahine, you must set the following option. This tells the plugin
not to try and mount the local filesystem to the container (which will not work over a network). Instead
it uses a Docker volume and copies the files across.

Additionally, if you are in a corporate network and there is a proxy, you can define this in the `proxy` option.
This will set the http and https proxy inside the container.

```yaml
custom:
pythonRequirements:
dockerizePip: true
dockerRemoteHost: true
Copy link
Contributor

@dschep dschep Nov 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the plugin maybe not actually have an option for this, and automatically do all the volume stuff if DOCKER_HOST is set?

proxy: http://yourproxy:8080
Copy link
Contributor

@dschep dschep Nov 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just merged #271. Please remove the proxy option as users can use the dockerEnv feature to pass proxies in.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok great, will do

```

[:checkered_flag: Windows notes](#checkered_flag-windows-dockerizepip-notes)

## Pipenv support :sparkles::cake::sparkles:
Expand Down
111 changes: 97 additions & 14 deletions lib/pip.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,71 @@ function installRequirements(targetFolder, serverless, options) {
}
serverless.cli.log(`Docker Image: ${dockerImage}`);

// Prepare bind path depending on os platform
const bindPath = dockerPathForWin(
options,
getBindPath(serverless, targetFolder)
);
var bindPath = ''; // Set this depending on whether remote host is being used.

// If Docker is using a remote host, we can't mount local files. Need to use data volume instead, and copy files in.
if (options.dockerRemoteHost) {
// docker volume create data-volume
serverless.cli.log('Remote docker option selected');
serverless.cli.log('Creating data volume');
cmdOptions = ['volume', 'create', 'data-volume']; // volume create data-volume
executeCmdAsSpawnSync(cmd, cmdOptions, options);

// docker create -v data-volume:/var/task --name helper (imagename) true
serverless.cli.log('Mounting data volume to helper container');
cmdOptions = [
'create',
'-v',
'data-volume:/var/task',
'--name',
'helper',
dockerImage,
'true'
];
executeCmdAsSpawnSync(cmd, cmdOptions, options);

// copy the files onto the volume
serverless.cli.log('Copying files onto volume');
cmdOptions = [
'cp',
dockerPathForWin(options, targetFolder),
'helper:/var/task'
]; // volume create data-volume
executeCmdAsSpawnSync(cmd, cmdOptions, options);

// remove the helper container - not needed any more
serverless.cli.log('Removing helper image');
cmdOptions = ['rm', 'helper']; // volume create data-volume
executeCmdAsSpawnSync(cmd, cmdOptions, options);

// Now set bindPath to the data volume (rather than a local folder)
bindPath = 'data-volume';
cmdOptions = [];
} else {
// Prepare bind path depending on os platform
bindPath = dockerPathForWin(
options,
getBindPath(serverless, targetFolder)
);
}

cmdOptions = [
'run',
'--name',
'python-reqs',
'-v',
`${bindPath}:/var/task:z`
];

if (options.proxy) {
cmdOptions.push(
'--env',
`http_proxy=${options.proxy}`,
'--env',
`https_proxy=${options.proxy}`
);
}

cmdOptions = ['run', '--rm', '-v', `${bindPath}:/var/task:z`];
if (options.dockerSsh) {
// Mount necessary ssh files to work with private repos
cmdOptions.push(
Expand Down Expand Up @@ -242,6 +300,37 @@ function installRequirements(targetFolder, serverless, options) {
const preparedPath = dockerPathForWin(options, targetFolder);
cmdOptions.push(getStripCommand(options, preparedPath));
}

try {
// execute the pip install (inside the container
executeCmdAsSpawnSync(cmd, cmdOptions, options);

if (options.dockerizePip) {
if (options.dockerRemoteHost) {
// copy the files back from the data volume
serverless.cli.log(
'Copying python libraries off docker container, ready for zipping'
);
cmdOptions = ['cp', 'python-reqs:/var/task/.', targetFolder]; // volume create data-volume
executeCmdAsSpawnSync(cmd, cmdOptions, options);
}
}
} finally {
if (options.dockerizePip) {
// clean up for next time.
serverless.cli.log('Removing container image');
cmdOptions = ['rm', 'python-reqs']; // remove data-volume
executeCmdAsSpawnSync(cmd, cmdOptions, options);
}
}

// If enabled slimming, delete files in slimPatterns
if (options.slim === true || options.slim === 'true') {
deleteFiles(options, targetFolder);
}
}

function executeCmdAsSpawnSync(cmd, cmdOptions, options) {
let spawnArgs = { shell: true };
if (process.env.SLS_DEBUG) {
spawnArgs.stdio = 'inherit';
Expand All @@ -261,10 +350,6 @@ function installRequirements(targetFolder, serverless, options) {
if (res.status !== 0) {
throw new Error(res.stderr);
}
// If enabled slimming, delete files in slimPatterns
if (options.slim === true || options.slim === 'true') {
deleteFiles(options, targetFolder);
}
}

/**
Expand All @@ -274,10 +359,8 @@ function installRequirements(targetFolder, serverless, options) {
* @return {string}
*/
function dockerPathForWin(options, path) {
if (process.platform === 'win32') {
return `"${path.replace(/\\/g, '/')}"`;
} else if (process.platform === 'win32' && !options.dockerizePip) {
return path;
if (process.platform === 'win32' && options.dockerizePip) {
return path.replace(/\\/g, '/');
}
return quote_single(path);
}
Expand Down