├── Dockerfile ├── README.md └── docker-run /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt-get update \ 4 | && apt-get install -y --no-install-recommends python-pip \ 5 | && apt-get -y --purge autoremove \ 6 | && rm -rf /var/lib/apt/lists/* 7 | 8 | RUN pip install docker-py 9 | 10 | COPY docker-run /docker-run 11 | RUN chmod 755 /docker-run 12 | 13 | ENTRYPOINT ["/docker-run"] 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-run 2 | #### *update packages or execute arbitrary commands inside running docker containers* 3 | 4 | When running multiple containers, updating the packeges, including security updates, in all of them can be a painful task. 5 | 6 | `docker-run` can be used to issue any arbitrary command on all running containers or a specified subset. 7 | 8 | Quick use: `docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec` 9 | 10 | By default *exec* will execute `date` command in all running containers 11 | 12 | - 13 | ### Usage 14 | 15 | The easiest way to use it is to create an alias, so you just execute `docker-run` directly as a regural command 16 | 17 | `alias docker-run='docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run'` 18 | 19 | If connecting to docker daemon over http you can specify the docker daemon host:port 20 | 21 | `alias docker-run='docker run --rm itech/docker-run --host http://127.0.0.1:4243'` 22 | 23 | -- 24 | 25 | ### Examples 26 | *assumig you have the alias* 27 | 28 | - `docker-run exec "uname -a"` 29 | *display the kernel in each container* 30 | 31 | - `docker-run update` 32 | *will update packages (only debian/ubuntu containers at the moment)* 33 | - `docker-run update -p python` 34 | *will only update python package* 35 | 36 | - `docker-run -c db1,db2 update postgresql` 37 | *only update the postgresql package on container db1 and db2* containers with these names must exist 38 | 39 | - `docker-run -c my_centos exec "yum update -y"` 40 | *will update a container names 'my_centos'* 41 | 42 | - `docker-run exec "date +'%Y-%m-%d' && uname -r"` 43 | *example of running multiple commands with different parameter for each* 44 | 45 | -- 46 | ## LICENSE 47 | Copyright 2014 iTech-Developer 48 | 49 | Licensed under the Apache License, Version 2.0 (the "License"); 50 | you may not use this file except in compliance with the License. 51 | You may obtain a copy of the License at 52 | 53 | http://www.apache.org/licenses/LICENSE-2.0 54 | 55 | Unless required by applicable law or agreed to in writing, software 56 | distributed under the License is distributed on an "AS IS" BASIS, 57 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 58 | See the License for the specific language governing permissions and 59 | limitations under the License. 60 | -------------------------------------------------------------------------------- /docker-run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from argparse import ArgumentParser 4 | from argparse import ArgumentError 5 | from docker import Client 6 | import sys 7 | import os 8 | 9 | def main(): 10 | program = sys.argv[0].strip(' .\/') 11 | 12 | parser = ArgumentParser(prog=program,usage='%(prog)s [OPTIONS] COMMAND [arg...]',epilog='Run \'%(prog)s COMMAND --help\' for more information on a command.') 13 | parser.add_argument('--version', action='version', version='%(prog)s 0.0.3') 14 | parser.add_argument('-c','--containers',dest='container',default='*',nargs='?',help='list of containers to execute separated by comma either container id or name, default: \'*\' for all containers') 15 | parser.add_argument('--host',dest='host',default='unix:///var/run/docker.sock',help='docker host address unix://SOCK_PATH or http://HOST:PORT') 16 | 17 | subparsers = parser.add_subparsers(prog=program,title='Available Commands',description=None,metavar='') 18 | 19 | # Create update parser 20 | parser_update = subparsers.add_parser('update', usage='%(prog)s [OPTIONS]',description='Update container packages e.g. perform apt-get upgrade',help='Update linux packages') 21 | parser_update.add_argument('-p','--packages',dest='package',default='*',nargs='*',help='list of packages to updated separated by space') 22 | parser_update.set_defaults(command='update') 23 | 24 | # Create exec parser 25 | parser_exec = subparsers.add_parser('exec', usage='%(prog)s "[CMD]"',description='Execute a single command, equivilant to docker exec CONTAINER COMMAND',help='Execute a command inside the container') 26 | parser_exec.add_argument('cmd',default='date',nargs='?',help='the command to execute should be quoted if the command has arguments') 27 | #parser_exec.add_argument('-s','--stream',dest='stream',action='store_true',help='Return command result as streaming response') 28 | parser_exec.set_defaults(command='exec') 29 | 30 | args = None 31 | try: 32 | args = parser.parse_args() 33 | except: 34 | print("Error while parsing arguments") 35 | sys.exit(1) 36 | 37 | process_command(args) 38 | 39 | 40 | def process_command(args): 41 | c = Client(base_url=args.host) 42 | try: 43 | result = c.ping() 44 | if "OK" == result: 45 | run_command(c,args) 46 | return 47 | except: 48 | pass 49 | 50 | c = Client(base_url='unix://tmp/docker.sock') 51 | try: 52 | result = c.ping() 53 | if "OK" == result: 54 | run_command(c,args) 55 | return 56 | except: 57 | pass 58 | 59 | print('Cannot connect to docker: %s'%(result)) 60 | sys.exit(1) 61 | 62 | def run_command(client, args): 63 | #print(args) 64 | containers = None 65 | if "*" == args.container: 66 | containers = client.containers() 67 | else: 68 | containers = args.container.split(",") 69 | 70 | for container in containers: 71 | c = None 72 | c_name = None 73 | if isinstance(container,str): 74 | c = container 75 | c_name = container 76 | else: 77 | c = container['Id'] 78 | # Ignore the current container where docker-run is executed 79 | hostname = os.getenv('HOSTNAME','') 80 | if len(hostname) > 0 and c.startswith(hostname): 81 | continue 82 | c_name = container['Names'][0].strip(' \/') 83 | 84 | print("*** %s ***\n"%(c_name)) 85 | if args.command == 'update': 86 | client.execute(c,"apt-get update") 87 | if "*" == args.package: 88 | print(client.execute(c,"apt-get -y upgrade ")) 89 | else: 90 | print(client.execute(c,"apt-get -y upgrade %s"%(" ".join(args.package)))) 91 | elif args.command == 'exec': 92 | print(client.execute(c,['/bin/bash','-c',args.cmd])) #stream=args.stream)) 93 | 94 | if __name__ == '__main__': 95 | main() 96 | --------------------------------------------------------------------------------