使用Python編排Dockerfile的代碼詳解
使用 python 替代 docker compose 編排容器
docker compose 是 docker 的容器編排工具,它是基于 YAML 配置,YAML 是一種配置文件格式,支持傳遞環(huán)境變量,但是對于復雜的容器編排顯得力不從心。
于是我便開發(fā)這個程序,可以像寫程序一樣編排 docker ,可以充分發(fā)揮程序猿的想象力。
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() 運行結(jié)果
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 腳本,轉(zhuǎn)換成 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
轉(zhuǎn)換成 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()怎么樣,只是換了另一種寫法,并沒有難度。下面我們就系統(tǒng)學習,如何使用 python 編排 docker 容器
實際上程序最終還是會轉(zhuǎn)化做 docker-compose 腳本執(zhí)行。這種寫法的有點是更靈活,你可以在程序中使用 if, while, 鏈接數(shù)據(jù)庫,等等操作,可以做更復雜的容器編排。
安裝依賴庫
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:
創(chuàng)建一個 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()) 運行結(jié)果
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()) 運行結(jié)果
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
創(chuàng)建 Composes
Services 對象創(chuàng)建服務,讓服務工作還需要 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')
運行結(jié)果
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' 這已經(jīng)是一個完善的 docker-compose 腳本了。使用 save 可以保存為 yaml 文件,這是使用 docker-compose -f development.yaml up 就可以啟動容器了。
Composes 對象同時也攜帶了完善的 docker-compose 命令和參數(shù),用于自我管理容器。
compose.up() 創(chuàng)建容器
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() 查看容器運行狀態(tài)
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.")
運行結(jié)果
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 對等的參數(shù),用法也基本相通。例如
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的代碼詳解的詳細內(nèi)容,更多關于Python編排Dockerfile的資料請關注腳本之家其它相關文章!
相關文章
Python 反轉(zhuǎn)字符串(reverse)的方法小結(jié)
這篇文章主要介紹了Python 反轉(zhuǎn)字符串(reverse)的方法小結(jié),需要的朋友可以參考下2018-02-02
Python實現(xiàn)文件下載、Cookie以及重定向的方法代碼
本文主要介紹了如何使用 Python 的 requests 模塊進行網(wǎng)絡請求操作,涵蓋了從文件下載、Cookie 處理到重定向與歷史請求等多個方面,通過詳細的示例代碼,展示了如何高效地實現(xiàn)各種網(wǎng)絡操作,幫助開發(fā)者更輕松地進行 HTTP 請求的處理和數(shù)據(jù)管理2025-02-02

