├── .gitmodules ├── run.sh ├── bin └── build.sh ├── README.md ├── configs └── build.cnf ├── .gitignore └── criu.py /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "shutit-library"] 2 | path = shutit-library 3 | url = https://github.com/ianmiell/shutit-library 4 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | [[ -z "$SHUTIT" ]] && SHUTIT="$1/shutit" 3 | [[ ! -a "$SHUTIT" ]] || [[ -z "$SHUTIT" ]] && SHUTIT="$(which shutit)" 4 | if [[ ! -a "$SHUTIT" ]] 5 | then 6 | echo "Must have shutit on path, eg export PATH=$PATH:/path/to/shutit_dir" 7 | exit 1 8 | fi 9 | $SHUTIT build -d bash --walkthrough "$@" 10 | if [[ $? != 0 ]] 11 | then 12 | exit 1 13 | fi 14 | -------------------------------------------------------------------------------- /bin/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | [[ -z "$SHUTIT" ]] && SHUTIT="$1/shutit" 3 | [[ ! -a "$SHUTIT" ]] || [[ -z "$SHUTIT" ]] && SHUTIT="$(which shutit)" 4 | if [[ ! -a "$SHUTIT" ]] 5 | then 6 | echo "Must have shutit on path, eg export PATH=$PATH:/path/to/shutit_dir" 7 | exit 1 8 | fi 9 | pushd .. 10 | $SHUTIT build -d bash "$@" 11 | if [[ $? != 0 ]] 12 | then 13 | popd 14 | exit 1 15 | fi 16 | popd 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Docker CRIU Demo 2 | ================ 3 | 4 | An automated, annotated, interactive demo of live container migration using Virtualbox, Vagrant and ShutIt: 5 | 6 | ``` 7 | pip install shutit 8 | git clone --recursive https://github.com/ianmiell/shutit-criu 9 | cd shutit-criu 10 | ./run.sh 11 | ``` 12 | 13 | [![asciicast](https://asciinema.org/a/9oamaf6mv1oiycpqmqtbzriw9.png)](https://asciinema.org/a/9oamaf6mv1oiycpqmqtbzriw9) 14 | -------------------------------------------------------------------------------- /configs/build.cnf: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # PLEASE NOTE: This file should be changed only by the maintainer. 3 | # PLEASE NOTE: This file is only sourced if the "shutit build" command is run 4 | # and this file is in the relative path: configs/build.cnf 5 | # This is to ensure it is only sourced if _this_ module is the 6 | # target. 7 | ############################################################################### 8 | # When this module is the one being built, which modules should be built along with it by default? 9 | # This feeds into automated testing of each module. 10 | [shutit.criu.criu.criu] 11 | shutit.core.module.build:yes 12 | # Allowed images as a regexp, eg ["ubuntu:12.*"], or [".*"], or ["centos"]. 13 | # It's recommended this is locked down as far as possible. 14 | shutit.core.module.allowed_images:["ubuntu:14.04"] 15 | 16 | # Aspects of build process 17 | [build] 18 | base_image:ubuntu:14.04 19 | 20 | # Volume arguments wanted as part of the build 21 | [target] 22 | volumes: 23 | 24 | [repository] 25 | name:criu 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #The MIT License (MIT) 2 | # 3 | #Copyright (C) 2014 OpenBet Limited 4 | # 5 | #Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | #this software and associated documentation files (the "Software"), to deal in 7 | #the Software without restriction, including without limitation the rights to 8 | #use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | #of the Software, and to permit persons to whom the Software is furnished to do 10 | #so, subject to the following conditions: 11 | # 12 | #The above copyright notice and this permission notice shall be included in all 13 | #copies or substantial portions of the Software. 14 | # 15 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | #ITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | #THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | #SOFTWARE. 22 | 23 | # Python 24 | *.pyc 25 | # Configs 26 | **.cnf 27 | !**build.cnf 28 | !**push.cnf 29 | !**defaults.cnf 30 | # Logs 31 | **.log 32 | # Nohups and outs 33 | nohup.out 34 | out 35 | # Lock files 36 | **.lck 37 | # Docs 38 | docs/_build 39 | # Artifacts 40 | artifacts/* 41 | # Resources 42 | *resources/* 43 | !*resources/README.md 44 | !*shutit_resources/README.md 45 | # Keys 46 | examples/ianmiellaws/context/pems/*.pem 47 | pubring.gpg~ 48 | secring.gpg 49 | examples/digital_ocean/context/access_token.dat 50 | # Show Config 51 | show_config/* 52 | build/* 53 | dist/* 54 | shutit.egg* 55 | -------------------------------------------------------------------------------- /criu.py: -------------------------------------------------------------------------------- 1 | """ShutIt module. See http://shutit.tk 2 | """ 3 | 4 | from shutit_module import ShutItModule 5 | 6 | 7 | class criu(ShutItModule): 8 | 9 | 10 | def build(self, shutit): 11 | # Some useful API calls for reference. See shutit's docs for more info and options: 12 | # 13 | # ISSUING BASH COMMANDS 14 | # shutit.send(send,expect=) - Send a command, wait for expect (string or compiled regexp) 15 | # to be seen before continuing. By default this is managed 16 | # by ShutIt with shell prompts. 17 | # shutit.multisend(send,send_dict) - Send a command, dict contains {expect1:response1,expect2:response2,...} 18 | # shutit.send_and_get_output(send) - Returns the output of the sent command 19 | # shutit.send_and_match_output(send, matches) 20 | # - Returns True if any lines in output match any of 21 | # the regexp strings in the matches list 22 | # shutit.send_until(send,regexps) - Send command over and over until one of the regexps seen in the output. 23 | # shutit.run_script(script) - Run the passed-in string as a script 24 | # shutit.install(package) - Install a package 25 | # shutit.remove(package) - Remove a package 26 | # shutit.login(user='root', command='su -') 27 | # - Log user in with given command, and set up prompt and expects. 28 | # Use this if your env (or more specifically, prompt) changes at all, 29 | # eg reboot, bash, ssh 30 | # shutit.logout(command='exit') - Clean up from a login. 31 | # 32 | # COMMAND HELPER FUNCTIONS 33 | # shutit.add_to_bashrc(line) - Add a line to bashrc 34 | # shutit.get_url(fname, locations) - Get a file via url from locations specified in a list 35 | # shutit.get_ip_address() - Returns the ip address of the target 36 | # shutit.command_available(command) - Returns true if the command is available to run 37 | # 38 | # LOGGING AND DEBUG 39 | # shutit.log(msg,add_final_message=False) - 40 | # Send a message to the log. add_final_message adds message to 41 | # output at end of build 42 | # shutit.pause_point(msg='') - Give control of the terminal to the user 43 | # shutit.step_through(msg='') - Give control to the user and allow them to step through commands 44 | # 45 | # SENDING FILES/TEXT 46 | # shutit.send_file(path, contents) - Send file to path on target with given contents as a string 47 | # shutit.send_host_file(path, hostfilepath) 48 | # - Send file from host machine to path on the target 49 | # shutit.send_host_dir(path, hostfilepath) 50 | # - Send directory and contents to path on the target 51 | # shutit.insert_text(text, fname, pattern) 52 | # - Insert text into file fname after the first occurrence of 53 | # regexp pattern. 54 | # shutit.delete_text(text, fname, pattern) 55 | # - Delete text from file fname after the first occurrence of 56 | # regexp pattern. 57 | # shutit.replace_text(text, fname, pattern) 58 | # - Replace text from file fname after the first occurrence of 59 | # regexp pattern. 60 | # ENVIRONMENT QUERYING 61 | # shutit.host_file_exists(filename, directory=False) 62 | # - Returns True if file exists on host 63 | # shutit.file_exists(filename, directory=False) 64 | # - Returns True if file exists on target 65 | # shutit.user_exists(user) - Returns True if the user exists on the target 66 | # shutit.package_installed(package) - Returns True if the package exists on the target 67 | # shutit.set_password(password, user='') 68 | # - Set password for a given user on target 69 | # 70 | # USER INTERACTION 71 | # shutit.get_input(msg,default,valid[],boolean?,ispass?) 72 | # - Get input from user and return output 73 | # shutit.fail(msg) - Fail the program and exit with status 1 74 | # 75 | shutit.send('rm -rf /tmp/vg-*') 76 | box = shutit.send_and_get_output('vagrant box list 2>/dev/null | grep kimh/criu') 77 | if box == '': 78 | shutit.send('vagrant box add https://atlas.hashicorp.com/kimh/boxes/criu',note='Download the criu vagrant box') 79 | shutit.send('mkdir /tmp/vg-1 && cd /tmp/vg-1 && vagrant init kimh/criu && vagrant up',note='Set up the criu VM') 80 | shutit.login(command='vagrant ssh',note='Log into the criu VM') 81 | shutit.send('docker run -d --name criu busybox sleep 999d',note='Start a container which runs for 999 days, and get its id') 82 | shutit.send('docker ps',note='Confirm it is now running') 83 | shutit.send('docker checkpoint criu',note='Now we checkpoint that container, which stops it (use --leave-running=true) to leave it running.') 84 | shutit.send('docker ps',note='Confirm it is now NOT running') 85 | shutit.send('docker restore criu',note='Restore the container with the process running') 86 | shutit.send('docker ps',note='It is running again!') 87 | shutit.send('docker rm -f criu',note='Now a more sophisticated example, where we stop a process with state and restore it.') 88 | shutit.send('''docker run --name np --rm busybox:latest /bin/sh -c 'i=0; while true; do echo -n "$i " | tee /tmp/output; i=$(expr $i + 1); sleep 1; done' &''',note='Start a container that outputs an incrementing number per second, and writes it to /tmp/output') 89 | shutit.send('sleep 10',note='wait 10 seconds - hit CTRL-] now!') 90 | shutit.send('docker checkpoint np',note='Stop the container and save its state.') 91 | shutit.send('sleep 10',note='wait 10 seconds - hit CTRL-] now!') 92 | shutit.send('docker restore np',note='Restore the state where we were') 93 | shutit.logout(note='Next we log out of the first VM.') 94 | shutit.send('mkdir -p /tmp/vg-2 && cd /tmp/vg-2 && vagrant init kimh/criu && vagrant up',note='Logged out. Now Initialise second VM and bring it up') 95 | shutit.login(command="""vagrant ssh -- 'docker run --name=foo -d busybox tail -f /dev/null && docker rm -f foo'""",note='Next command required due to a bug in CRIU') 96 | shutit.send('curl -L -o /tmp/docker-migrate.sh https://gist.githubusercontent.com/kimh/79f7bcb195466acea39a/raw/ca0965d90c850dcbe54654a6002678fff333d408 && chmod +x /tmp/docker-migrate.sh',note='Download the helper migrate script') 97 | shutit.send('/tmp/docker-migrate.sh np /tmp/vg-1 /tmp/vg-2',note='Now migrate the container from vg-1 to vg-2') 98 | shutit.send('cd /tmp/vg-2') 99 | shutit.login(command='vagrant ssh',note='Now visit the second VM') 100 | shutit.send('docker ps',note='Check that np is now running here') 101 | shutit.send('docker exec np cat /tmp/output',note='cat the file it writes to') 102 | shutit.send('docker exec np cat /tmp/output',note='cat it again to show it is still running') 103 | shutit.pause_point('') 104 | return True 105 | 106 | def get_config(self, shutit): 107 | # CONFIGURATION 108 | # shutit.get_config(module_id,option,default=None,boolean=False) 109 | # - Get configuration value, boolean indicates whether the item is 110 | # a boolean type, eg get the config with: 111 | # shutit.get_config(self.module_id, 'myconfig', default='a value') 112 | # and reference in your code with: 113 | # shutit.cfg[self.module_id]['myconfig'] 114 | return True 115 | 116 | def test(self, shutit): 117 | # For test cycle part of the ShutIt build. 118 | return True 119 | 120 | def finalize(self, shutit): 121 | # Any cleanup required at the end. 122 | return True 123 | 124 | def is_installed(self, shutit): 125 | return False 126 | 127 | 128 | def module(): 129 | return criu( 130 | 'shutit.criu.criu.criu', 1183039072.00, 131 | description='', 132 | maintainer='', 133 | delivery_methods=['bash'], 134 | depends=['tk.shutit.vagrant.vagrant.vagrant'] 135 | ) 136 | 137 | --------------------------------------------------------------------------------