使用 python 替代 docker compose 编排容器
docker compose 是 docker 的容器编排工具,它是基于 yaml 配置,yaml 是一种配置文件格式,支持传递环境变量,但是对于复杂的容器编排显得力不从心。
于是我便开发这个程序,可以像写程序一样编排 docker ,可以充分发挥程序猿的想象力。
pip install netkiller-devops
编排 dockerfile
from netkiller.docker import *
 
# 实例化 dockerfile() 对象
nginx = dockerfile()
 
# 基于什么镜像
nginx.image('nginx:latest')
 
# 配置挂载卷
nginx.volume(['/etc/nginx','/var/log/nginx','/opt'])
 
# 运行脚本
nginx.run('apt update -y && apt install -y procps')
 
# 暴漏端口
nginx.expose(['80','443'])
 
# 设置工作目录
nginx.workdir('/opt')
 
# 打印 dockerfile
nginx.show()		运行结果
from nginx:latest
volume ["/etc/nginx","/var/log/nginx","/opt"]
run apt update -y && apt install -y procps
expose 80 443
workdir /opt
另一种写法
from netkiller.docker import *
 
nginx = dockerfile() 
nginx.image('nginx:latest').volume(['/etc/nginx','/var/log/nginx']).run('apt update -y && apt install -y procps').expose(['80','443']).workdir('/opt')
nginx.render()
nginx.save('/tmp/dockerfile')构建 docker 镜像
from netkiller.docker import *
 
# 编排 docker 镜像
dockerfile = dockerfile()
dockerfile.image('openjdk:8').volume(['/srv']).run(
    'apt update -y && apt install -y procps net-tools iputils-ping iproute2 telnet'
).expose(['80', '443']).workdir('/srv')
 
# 通过 service 设置镜像名称是 netkiller:openjdk8
image = services('image')
image.build(dockerfile)
image.image('netkiller:openjdk8')
 
# 构建镜像
demo = composes('demo')
demo.version('3.9')
demo.services(image)
demo.build()		完整演示
#!/usr/bin/python3
#-*- coding: utf-8 -*-
##############################################
# home	: http://netkiller.github.io
# author: neo <netkiller@msn.com>
# upgrade: 2021-11-17
##############################################
try:
	import os,  sys
	module = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
	print(module)
	sys.path.insert(0,module)
	from netkiller.docker import *
except importerror as err:
	print("%s" %(err))
 
dockerfile = dockerfile() 
# dockerfile.label({'org.opencontainers.image.authors':'netkiller'})
dockerfile.image('openjdk:8-alpine')
# dockerfile.image('openjdk:8')
dockerfile.env({'rocketmq_version':'4.9.2','rocketmq_home':'/srv/rocketmq', 'path':'${rocketmq_home}/bin:$path'}) # 'java_opt':'"${java_opt} -server -xms512m -xmx2048m -xmn128m"'
dockerfile.arg({'user':'rocketmq', 'group':'nogroup'})
dockerfile.run('wget https://dlcdn.apache.org/rocketmq/4.9.2/rocketmq-all-4.9.2-bin-release.zip && unzip rocketmq-all-4.9.2-bin-release.zip')
dockerfile.run('mv rocketmq-4.9.2 /srv/rocketmq-4.9.2 && rm -rf rocketmq-all-4.9.2-bin-release.zip')
dockerfile.run('ln -s /srv/rocketmq-${rocketmq_version} /srv/rocketmq')
dockerfile.run('adduser -s -d ${user}')
dockerfile.run(['chown ${user}:${group} -r /srv/rocketmq-${rocketmq_version}'])
dockerfile.expose(['9876'])
dockerfile.expose(['10909','10911','10912'])
dockerfile.copy('docker-entrypoint.sh','/srv/docker-entrypoint.sh')
dockerfile.run('chmod a+x /srv/docker-entrypoint.sh')
dockerfile.entrypoint('["/srv/docker-entrypoint.sh"]') 
dockerfile.workdir('${rocketmq_home}')
# dockerfile.render()
# dockerfile.save('/tmp/dockerfile')
 
rocketmq = services('rocketmq')
rocketmq.build(dockerfile).image('registry.netkiller.cn/rocketmq/rocketmq:4.9.2').container_name('rocketmq')
# rocketmq.entrypoint('/srv/rocketmq/bin/mqnamesrv')
# rocketmq.ports('9876:9876').command('/srv/rocketmq/bin/mqnamesrv')
 
dockerfile = dockerfile() 
dockerfile.image('registry.netkiller.cn/rocketmq/rocketmq:4.9.2')
dockerfile.run('ln -s /srv/rocketmq-${rocketmq_version} /srv/mqnamesrv')
dockerfile.cmd('/srv/mqnamesrv/bin/mqnamesrv')
dockerfile.workdir('/srv/mqnamesrv')
dockerfile.user('rocketmq:nogroup')
dockerfile.volume([
 	'/home/rocketmq/logs/rocketmqlogs'
])
 
mqnamesrv = services('mqnamesrv')
mqnamesrv.build(dockerfile).image('registry.netkiller.cn/rocketmq/mqnamesrv:4.9.2').container_name('mqnamesrv').ports('9876:9876')
mqnamesrv.command('mqnamesrv')
 
dockerfile = dockerfile() 
dockerfile.image('registry.netkiller.cn/rocketmq/rocketmq:4.9.2')
dockerfile.run('ln -s /srv/rocketmq-${rocketmq_version} /srv/mqbroker')
dockerfile.cmd('/srv/rocketmq/bin/mqbroker')
dockerfile.workdir('/srv/mqbroker')
dockerfile.user('rocketmq:nogroup')
dockerfile.volume([
 	'/home/rocketmq/logs/rocketmqlogs'
])
 
mqbroker = services('mqbroker')
mqbroker.build(dockerfile).image('registry.netkiller.cn/rocketmq/mqbroker:4.9.2').container_name('mqbroker').ports(['10909:10909','10911:10911','10912:10912'])
mqbroker.command('mqbroker -n mqnamesrv:9876 -c /srv/rocketmq/conf/broker.conf')
mqbroker.volumes(['/tmp/logs:/home/rocketmq/logs/rocketmqlogs'])
 
composes = composes('test')
composes.version('3.9')
composes.services(rocketmq)
composes.services(mqnamesrv)
composes.services(mqbroker)
 
 
# cat >> /srv/docker-entrypoint.sh <<'eof'
# eof
 
entrypoint='''#!/bin/sh
if [ "$1" = 'mqnamesrv' ]; then
	exec /srv/rocketmq/bin/mqnamesrv
fi
exec "$@"
'''
 
if __name__ == '__main__':
	try:
		docker = docker({'docker_host':'ssh://root@192.168.30.11','namesrv_addr':'localhost:9876'}) 
		docker.createfile('rocketmq/rocketmq/docker-entrypoint.sh',entrypoint)
		docker.environment(composes)
		docker.main()
	except keyboardinterrupt:
		print ("crtl+c pressed. shutting down.")运行
python3 demo.py -e test -b rocketmq
快速入门,首先我们参照这个 docker-compose.yaml 脚本,转换成 python 脚本。
version: '3.9' services: nginx: container_name: nginx environment: - tz=asia/shanghai extra_hosts: - db.netkiller.cn:127.0.0.1 - cache.netkiller.cn:127.0.0.1 - api.netkiller.cn:127.0.0.1 hostname: www.netkiller.cn image: nginx:latest ports: - 80:80 - 443:443 restart: always volumes: - /tmp:/tmp
转换成 python 语言之后
from netkiller.docker import *
service = services('nginx')
service.image('nginx:latest')
service.container_name('nginx')
service.restart('always')
service.hostname('www.netkiller.cn')
service.extra_hosts(['db.netkiller.cn:127.0.0.1','cache.netkiller.cn:127.0.0.1','api.netkiller.cn:127.0.0.1'])
service.environment(['tz=asia/shanghai'])
service.ports(['80:80','443:443'])
service.volumes(['/tmp:/tmp'])
# service.debug()
# print(service.dump())
compose = composes('development')
compose.version('3.9')
compose.services(service)
# print (compose.debug())
print(compose.dump())
compose.save()怎么样,只是换了另一种写法,并没有难度。下面我们就系统学习,如何使用 python 编排 docker 容器
实际上程序最终还是会转化做 docker-compose 脚本执行。这种写法的有点是更灵活,你可以在程序中使用 if, while, 链接数据库,等等操作,可以做更复杂的容器编排。
安装依赖库
neo@macbook-pro-neo ~ % pip install netkiller-devops
确认是否安装成功
neo@macbook-pro-neo ~ % pip show netkiller-devops name: netkiller-devops version: 0.2.4 summary: devops of useful deployment and automation home-page: https://github.com/oscm/devops author: neo chen author-email: netkiller@msn.com license: bsd location: /usr/local/lib/python3.9/site-packages requires: pyttsx3, requests, redis, pyyaml required-by:
创建一个 services
from netkiller.docker import *
 
service =  services('nginx')
service.image('nginx:latest')
service.container_name('nginx')
service.restart('always')
service.hostname('www.netkiller.cn')
service.extra_hosts(['db.netkiller.cn:127.0.0.1','cache.netkiller.cn:127.0.0.1','api.netkiller.cn:127.0.0.1'])
service.environment(['tz=asia/shanghai'])
service.ports(['80:80','443:443'])
service.volumes(['/tmp:/tmp'])
# service.debug()
print(service.dump())		运行结果
nginx: container_name: nginx environment: - tz=asia/shanghai extra_hosts: - db.netkiller.cn:127.0.0.1 - cache.netkiller.cn:127.0.0.1 - api.netkiller.cn:127.0.0.1 hostname: www.netkiller.cn image: nginx:latest ports: - 80:80 - 443:443 restart: always volumes: - /tmp:/tmp
来一个复杂的演示
for i in range(10) :
    cluster =  services('nginx-'+str(i))
    cluster.image('nginx:latest').container_name('nginx-'+str(i)).restart('always').hostname('www'+str(i)+'.netkiller.cn')
    cluster.ports(['8{port}:80'.format(port=i)])
    print(cluster.dump())		运行结果
nginx-0: container_name: nginx-0 hostname: www0.netkiller.cn image: nginx:latest ports: - 80:80 restart: always nginx-1: container_name: nginx-1 hostname: www1.netkiller.cn image: nginx:latest ports: - 81:80 restart: always nginx-2: container_name: nginx-2 hostname: www2.netkiller.cn image: nginx:latest ports: - 82:80 restart: always nginx-3: container_name: nginx-3 hostname: www3.netkiller.cn image: nginx:latest ports: - 83:80 restart: always nginx-4: container_name: nginx-4 hostname: www4.netkiller.cn image: nginx:latest ports: - 84:80 restart: always nginx-5: container_name: nginx-5 hostname: www5.netkiller.cn image: nginx:latest ports: - 85:80 restart: always nginx-6: container_name: nginx-6 hostname: www6.netkiller.cn image: nginx:latest ports: - 86:80 restart: always nginx-7: container_name: nginx-7 hostname: www7.netkiller.cn image: nginx:latest ports: - 87:80 restart: always nginx-8: container_name: nginx-8 hostname: www8.netkiller.cn image: nginx:latest ports: - 88:80 restart: always nginx-9: container_name: nginx-9 hostname: www9.netkiller.cn image: nginx:latest ports: - 89:80 restart: always
创建 composes
services 对象创建服务,让服务工作还需要 composes 对象。
from netkiller.docker import *
 
service =  services('nginx')
service.image('nginx:latest')
service.container_name('nginx')
service.restart('always')
service.hostname('www.netkiller.cn')
service.extra_hosts(['db.netkiller.cn:127.0.0.1','cache.netkiller.cn:127.0.0.1','api.netkiller.cn:127.0.0.1'])
service.environment(['tz=asia/shanghai'])
service.ports(['80:80','443:443'])
service.volumes(['/tmp:/tmp'])
 
compose = composes('development')
compose.version('3.9')
compose.services(service)
# print (compose.debug())
print(compose.dump())
compose.save()
# compose.save('/tmp/docker-compose.yaml')		
 
运行结果
services:
  nginx:
    container_name: nginx
    environment:
    - tz=asia/shanghai
    extra_hosts:
    - db.netkiller.cn:127.0.0.1
    - cache.netkiller.cn:127.0.0.1
    - api.netkiller.cn:127.0.0.1
    hostname: www.netkiller.cn
    image: nginx:latest
    ports:
    - 80:80
    - 443:443
    restart: always
    volumes:
    - /tmp:/tmp
version: '3.9'		这已经是一个完善的 docker-compose 脚本了。使用 save 可以保存为 yaml 文件,这是使用 docker-compose -f development.yaml up 就可以启动容器了。
composes 对象同时也携带了完善的 docker-compose 命令和参数,用于自我管理容器。
compose.up() 创建容器
compose = composes('development')
compose.version('3.9')
compose.services(service)
compose.up()
 
compose.start() 启动已存在的容器
compose = composes('development')
compose.version('3.9')
compose.services(service)
compose.start()
 
compose.stop() 停止已存在的容器
compose = composes('development')
compose.version('3.9')
compose.services(service)
compose.stop()
 
compose.restart() 重启已存在的容器
compose = composes('development')
compose.version('3.9')
compose.services(service)
compose.restart()
 
compose.rm() 销毁已存在的容器
compose = composes('development')
compose.version('3.9')
compose.services(service)
compose.rm()
 
compose.logs() 查看容器日志
compose = composes('development')
compose.version('3.9')
compose.services(service)
compose.logs()
 
compose.ps() 查看容器运行状态
compose = composes('development')
compose.version('3.9')
compose.services(service)
compose.ps()容器管理
docker 对象是让我们摆脱 docker-compose 这个命令,它将接管 docker-compose 这个命令,进行自我管理。
#!/usr/bin/python3
#-*- coding: utf-8 -*-
##############################################
# home	: http://netkiller.github.io
# author: neo <netkiller@msn.com>
# upgrade: 2021-09-05
##############################################
try:
	import os,  sys
	module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
	sys.path.insert(0,module)
	from netkiller.docker import *
except importerror as err:
	print("%s" %(err))
 
nginx =  services('nginx')
nginx.image('nginx:latest')
nginx.container_name('nginx')
nginx.restart('always')
nginx.hostname('www.netkiller.cn')
nginx.environment(['ta=asia/shanghai'])
nginx.ports(['80:80'])
 
compose = composes('development')
compose.version('3.9')
compose.services(nginx)
compose.workdir('/tmp/compose')
 
if __name__ == '__main__':
	try:
		docker = docker()
		docker.environment(compose)
		docker.main()
	except keyboardinterrupt:
		print ("crtl+c pressed. shutting down.")		
 
运行结果
neo@macbook-pro-neo ~ % python3 docker.py
usage: docker.py [options] up|rm|start|stop|restart|logs|top|images|exec <service>
 
options:
  -h, --help         show this help message and exit
  --debug            debug mode
  -d, --daemon       run as daemon
  --logfile=logfile  logs file.
  -l, --list         following logging
  -f, --follow       following logging
  -c, --compose      show docker compose
  -e, --export       export docker compose
 
homepage: http://www.netkiller.cn       author: neo <netkiller@msn.com>		docker 对象提供了与 docker-compose 对等的参数,用法也基本相通。例如
python3 docker.py up = docker-compose up python3 docker.py up -d nginx = docker-compose up -d nginx python3 docker.py restart nginx = docker-compose restart nginx python3 docker.py ps = docker-compose ps python3 docker.py logs nginx = docker-compose logs nginx
使用 -c 可以查看 compose yaml 脚本,使用 -e 可以导出 docker compose yaml
演示例子
redis 主从配置
例18.1.redis master/slave
from netkiller.docker import *
 
image = 'redis:latest'
requirepass='11223344'
 
compose = composes('redis-master-slave')
compose.version('3.9')
 
master =  services('master')
master.image(image)
master.container_name('master')
master.restart('always')
master.environment(['tz=asia/shanghai'])
master.ports('6379:6379')
master.volumes(['/tmp/master:/data'])
master.sysctls(['net.core.somaxconn=1024'])
master.command([
	'--requirepass '+requirepass,
	'--appendonly yes'])
# master.debug()
# print(master.dump())
compose.services(master)
 
 
for i in range(5) :
    slave =  services('slave-'+str(i))
    slave.image(image).container_name('slave-'+str(i)).restart('always')
    slave.ports(['638{port}:6379'.format(port=i)]).environment(['tz=asia/shanghai'])
    slave.volumes(['/tmp/slave{n}:/data'.format(n=i)])
    slave.sysctls(['net.core.somaxconn=1024']).command([
        '--slaveof master 6379',
        '--masterauth '+requirepass,
        '--requirepass ' + requirepass,
        '--appendonly yes'
    ])
 
    # print(cluster.dump())
    compose.services(slave)
 
# print (compose.debug())
print(compose.dump())
# compose.save()
compose.up()					以上就是使用python编排dockerfile的代码详解的详细内容,更多关于python编排dockerfile的资料请关注代码网其它相关文章!
            
                                            
                                            
                                            
                                            
                                            
发表评论