捡垃圾之后怎么玩? 篇二:如何借助Docker和python实现DDNS

2022-10-08 18:02:06 9点赞 94收藏 11评论

1 引言

首先声明一下使用场景,本文适用拥有动态公网ip的朋友,如果没有的话,那么这篇文章并不适合你,可以参照前面一篇中frp的内容进行食用。

本文已经考虑到大家在使用上的障碍,为了保障体验的一致,最后后附上源码,基本只需要按照本文的流程一步步设置下去,就可以实现对应的功能。

  • 为什需要需要ddns?


因为我们在使用nas或者服务器部署的docker应用的时候,难免会涉及到公网的问题。如果没有公网的话,那么你只可以在你的局域网内访问你的应用的,而这又极大地限制了使用场景。但是现在家用宽带极少会提供公网IP,即便是提供了,所给的也是动态的公网ip,通常会在几天之内变动一次,或者是每次断电后变动一次。这种情形下,采用IP+端口形式的访问就会失效。为了应对这种情况,有很多解决方案,而DDNS方案,就是采用了将ip与域名紧紧绑定在一起,每次公网变动的时候就将变动后的ip绑定到域名上,这样不管ip如何变化,都可以通过域名+端口的形式进行绑定。

  • 为什么不采用软路由或者其他路由上的ddns,或者站内有人写过的docker方式部署的ddns?

第一,软路由或者其他路由器部署ddns,具有不特定性,会因为不同路由器的设置方式不同而产生不同,而且相对来说可能对小白不是很友好,也不具有可复制性;第二,使用docker方式部署的ddns,在笔者自己动手试验后,并没有成功,可能是笔者自己的原因,但是为了保障结果的可复制性,还是最终决定给大家介绍这种稍显原始的方式。

  • 为什么使用阿里云而不是dnspot或者其他的域名服务商?

一方面,笔者自己的云服务器以及其他服务基本采用的都是阿里的方案,便于统一的维护,因此域名解析服务还是采用的阿里的;另一方面,由于腾讯对于英雄联盟皮肤的定价问题,除了微信这种不得不使用的软件,基本上能不用腾讯就不用腾讯的,这是个人偏好问题。最后,还不是因为其他的没有去研究过,我不会嘛。

  • 为什么使用chronos?

因为chronos是一个可视化的界面来运行python,操作上面足够简便。当然,如果有一定linux和docker基础的,也可以通过直接使用docker部署py脚本加crontab定时运行的方式来实现功能。但是,考虑到读者的水平不一,本文尽量以一种大家能够看的懂最简便的方式来实现功能,保持可复制性。

2 准备工作

一条具有公网IP的宽带,一般只有电信和联通可以提供,具体的还得去问一下当地的服务商,其次就是需要一个域名,一个很便宜的就行了,基本上十块钱左右一年的有一大把。

除了域名之外,还需要知道的就是阿里云的accessID与access sercet,具体可以参考站内这篇文章

如果想在基本功能之上,加上一个变动ip即通知到你的微信,那么还需要的就是企业微信的AgentId、Secret、CompanyId三个参数,参照笔者之前这篇文章进行获取。

3 chronos的安装

这里还是需要重申一下,需要一台支持docker的设备,可以是捡垃圾来的设备,也可以是nas。但是,为了维持可复制性,还是推荐x86架构的设备,因为笔者在自己刷了armbian的玩客云上面试过,确实无法部署成功,不知道S905芯片的设备或者rk3399的设备是否可以支持,值友们如果有试过的可以告知一声。

此处默认已经安装好了docker,输入以下代码:

docker run -p 5000:5000 -v /mnt/docker/chronos:/chronos simsemand/chronos

待运行成功且没有报错,输入ip:5000即可进入头图中的页面,这样就代表部署成功了。

4 python部分的实现

这里想说明一下的是,这里想通过功能分解的方式进行展示。有些功能并不是必要,如微信推送公网ip的变动。这一部分如果不需要,那么就可以删掉对应的部分。作者最后准备给上两个版本的代码,供大家下载使用。

4.1 公网IP的获取

import os

ipv4=os.popen("curl ifconfig.me").read()

4.2 推送消息到微信

设置方面还是参照笔者之前的那篇文章,以下仅贴出代码。需要替换的部分就是你自己的AgentId、Secret、CompanyId。这一部分内容来源于网上,由于已经有现成的轮子,就不再重复造轮子了。

def send2wechat(self,message):

AgentId = ''

Secret = ''

CompanyId = ''

# 通行密钥

ACCESS_TOKEN = None

# 如果本地保存的有通行密钥且时间不超过两小时,就用本地的通行密钥

if os.path.exists('ACCESS_TOKEN.txt'):

txt_last_edit_time = os.stat('ACCESS_TOKEN.txt').st_mtime

now_time = time.time()

if now_time - txt_last_edit_time < 7200: # 官方说通行密钥2小时刷新

with open('ACCESS_TOKEN.txt', 'r') as f:

ACCESS_TOKEN = f.read()

# print(ACCESS_TOKEN)

# 如果不存在本地通行密钥,通过企业ID和应用Secret获取

if not ACCESS_TOKEN:

r = requests.post(

f'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={CompanyId}&corpsecret={Secret}').json()

ACCESS_TOKEN = r["access_token"]

# print(ACCESS_TOKEN)

# 保存通行密钥到本地ACCESS_TOKEN.txt

with open('ACCESS_TOKEN.txt', 'w', encoding='utf-8') as f:

f.write(ACCESS_TOKEN)

# 要发送的信息格式

data = {

"touser": "@all",

"msgtype": "text",

"agentid": f"{AgentId}",

"text": {"content": f"{message}"}

}

# 字典转成json,不然会报错

data = json.dumps(data)

# 发送消息

r = requests.post(

f'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={ACCESS_TOKEN}', data=data)

# print(r.json())

4.3 汇总

关于域名解析部分的代码也是来源自网络,经笔者修改后如下所示。

需要注意的是,需要填入的是access_key_id、access_key_secret、domain 、name_ipv4,前两个即所获得的阿里云密钥,domian是你的域名,而name_ipv4则建议填入www,之后你的访问形式即www.abc.abc(即你的域名):端口号。

import json,requests,re,os

from urllib.request import urlopen

from aliyunsdkcore.client import AcsClient

from aliyunsdkalidns.request.v20150109.DescribeSubDomainRecordsRequest import DescribeSubDomainRecordsRequest

class Dnscontroller:

# 阿里云个人中心获取Access_Key_Id和Access_Key_Secret

access_key_id = ""

access_key_secret = ""

# 填写你的主域名

domain = ""

# 要进行ipv4 ddns解析的子域名(主机记录)

name_ipv4 = ""

# 解析记录类型,一般为A记录

record_type = "A"

# 区域

region = "cn-hangzhou"

def __init__(self):

self.client = AcsClient(

self.access_key_id,

self.access_key_secret,

self.region

)

def send2wechat(self,message):

AgentId = ''

Secret = ''

CompanyId = ''

# 通行密钥

ACCESS_TOKEN = None

# 如果本地保存的有通行密钥且时间不超过两小时,就用本地的通行密钥

if os.path.exists('ACCESS_TOKEN.txt'):

txt_last_edit_time = os.stat('ACCESS_TOKEN.txt').st_mtime

now_time = time.time()

if now_time - txt_last_edit_time < 7200: # 官方说通行密钥2小时刷新

with open('ACCESS_TOKEN.txt', 'r') as f:

ACCESS_TOKEN = f.read()

# print(ACCESS_TOKEN)

# 如果不存在本地通行密钥,通过企业ID和应用Secret获取

if not ACCESS_TOKEN:

r = requests.post(

f'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={CompanyId}&corpsecret={Secret}').json()

ACCESS_TOKEN = r["access_token"]

# print(ACCESS_TOKEN)

# 保存通行密钥到本地ACCESS_TOKEN.txt

with open('ACCESS_TOKEN.txt', 'w', encoding='utf-8') as f:

f.write(ACCESS_TOKEN)

# 要发送的信息格式

data = {

"touser": "@all",

"msgtype": "text",

"agentid": f"{AgentId}",

"text": {"content": f"{message}"}

}

# 字典转成json,不然会报错

data = json.dumps(data)

# 发送消息

r = requests.post(

f'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={ACCESS_TOKEN}', data=data)

# print(r.json())

# 添加新的域名解析记录

def add(self, DomainName, RR, Type, Value):

from aliyunsdkalidns.request.v20150109.AddDomainRecordRequest import AddDomainRecordRequest

request = AddDomainRecordRequest()

request.set_accept_format('json')

request.set_DomainName(DomainName)

request.set_RR(RR)

request.set_Type(Type)

request.set_Value(Value)

response = self.client.do_action_with_exception(request)

# 修改域名解析记录

def update(self, RecordId, RR, Type, Value):

from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest

request = UpdateDomainRecordRequest()

request.set_accept_format('json')

request.set_RecordId(RecordId)

request.set_RR(RR)

request.set_Type(Type)

request.set_Value(Value)

response = self.client.do_action_with_exception(request)

# 获取公网IP并进行修改

def Get_IPv4(self):

request = DescribeSubDomainRecordsRequest()

request.set_accept_format('json')

request.set_DomainName(self.domain)

request.set_SubDomain(self.name_ipv4 + '.' + self.domain)

response = self.client.do_action_with_exception(request) # 获取域名解析记录列表

domain_list = json.loads(response) # 将返回的JSON数据转化为Python能识别的

# 获取IP

ipv4=os.popen("curl ifconfig.me").read()

if domain_list['TotalCount'] == 0:

self.add(self.domain, self.name_ipv4, self.record_type, ipv4)

print("新建域名解析成功")

elif domain_list['TotalCount'] == 1:

if domain_list['DomainRecords']['Record'][0]['Value'].strip() != ipv4.strip():

self.send2wechat('IP地址发生变更,现在的IP为{}'.format(ipv4))

self.update(domain_list['DomainRecords']['Record'][0]['RecordId'], self.name_ipv4, self.record_type,

ipv4)

print("修改域名解析成功")

else:

print("IPv4地址没变")


elif domain_list['TotalCount'] > 1:

# 删除所有解析过的记录,并重新添加新的解析记录

from aliyunsdkalidns.request.v20150109.DeleteSubDomainRecordsRequest import DeleteSubDomainRecordsRequest

request = DeleteSubDomainRecordsRequest()

request.set_accept_format('json')

request.set_DomainName(self.domain)

request.set_RR(self.name_ipv4)

response = self.client.do_action_with_exception(request)

self.add(self.domain, self.name_ipv4, self.record_type, ipv4)

print("修改域名解析成功")

if __name__ == "__main__":

Dnscontroller().Get_IPv4()

关于代码部分,本文代码填入对应信息之后保存即可

5 chronos的设置

完成了上面的步骤之后,后面就到了chronos的设置部分了

新建脚本


新建脚本新建脚本

填入需要的依赖:

aliyun-python-sdk-core==2.13.36

aliyun-python-sdk-domain==3.14.7

aliyun-python-sdk-alidns==2.6.32

requests==2.25.1

点击保存,然后点击安装依赖

填入依赖填入依赖

粘贴修改后的脚本,然后保存,运行:

放入脚本放入脚本

在这个下面会显示运行结果,可以点开查看一下是否运行成功

设置间隔运行

这个根据自己的需要来进行,笔者填入的是每隔一分钟检查一遍公网ip是否发生变动

设置间隔运行设置间隔运行

最后,点击enable和execute,就可以不用管它了,你的服务器就会勤勤恳恳的每分钟给你检查一次,如果有变动的话就会自行更改。

6 总结

本文到此结束,希望大家使用愉快!后面可能主要精力想更新一点obsidian的内容,还希望大家多多支持哇。如果有什么想看的docker应用或者想实现的功能,也可以留言告知,能力范围内的一定安排!


作者声明本文无利益相关,欢迎值友理性交流,和谐讨论~

展开 收起

WPS 金山软件 WPS 超级会员 3年卡

WPS 金山软件 WPS 超级会员 3年卡

264.1元起

WPS 金山软件 超级会员15个月卡+哔哩哔哩大会员年卡

WPS 金山软件 超级会员15个月卡+哔哩哔哩大会员年卡

暂无报价

ihuman 洪恩 识字子集拼音思维ABC会员永久包3-6岁儿童早教启蒙礼物玩具 识字会员终身包

ihuman 洪恩 识字子集拼音思维ABC会员永久包3-6岁儿童早教启蒙礼物玩具 识字会员终身包

268元起

Microsoft 微软 OFFICE 365 家庭版 会员

Microsoft 微软 OFFICE 365 家庭版 会员

105元起

Microsoft 微软 Office 365 个人版

Microsoft 微软 Office 365 个人版

177元起

Microsoft 微软 365家庭版一年

Microsoft 微软 365家庭版一年

235元起

统信 UOS桌面操作系统V20/适用于国产型号/官方正版授权/国产专用

统信 UOS桌面操作系统V20/适用于国产型号/官方正版授权/国产专用

598元起

WPS 金山软件 超级会员2年卡 赠AI会员

WPS 金山软件 超级会员2年卡 赠AI会员

187.15元起

Microsoft 微软 OFFICE 365 个人版 办公软件

Microsoft 微软 OFFICE 365 个人版 办公软件

199元起

WPS 金山软件 会员季卡

WPS 金山软件 会员季卡

37.05元起

WPS超级会员Pro套餐4年卡1488天官方正版pdf转word排版

WPS超级会员Pro套餐4年卡1488天官方正版pdf转word排版

暂无报价

WPS 金山软件 超级会员年卡+芒果TV年卡

WPS 金山软件 超级会员年卡+芒果TV年卡

158元起

365office365OfficePLUS Microsoft365 12 -

365office365OfficePLUS Microsoft365 12 -

235元起

WPS 金山软件 AI会员1年 金山办公软件官方正版

WPS 金山软件 AI会员1年 金山办公软件官方正版

188元起

WPS 金山软件 超级会员季卡

WPS 金山软件 超级会员季卡

33.05元起

国行版 Switch体感游戏套装 《健身环大冒险》

国行版 Switch体感游戏套装 《健身环大冒险》

379元起
11评论

  • 精彩
  • 最新
  • 推荐docker镜像:ddnsgo

    校验提示文案

    提交
    有看过相关的,这个主要也是开拓一下思路,而且加了一个微信通知公网ip变动的功能嘛,理论上能实现的功能可以无限添加的

    校验提示文案

    提交
    虽然有更方便的选择,不过折腾的乐趣不就在于更多/更好的解决办法么?而且乐于分享,给你这种精神点赞。还有看着代码没对齐的样子很难受,还好你附上了源码 [鼓掌]

    校验提示文案

    提交
    还有1条回复
    收起所有回复
  • 虽然我不知道,你这个是干啥的,但是也点个赞吧。。

    校验提示文案

    提交
    就比如说你有公网ip吧,但是一般家用的都是会变动的。如果你有远程桌面或者部署了其他的服务,那么ip一旦变动,你就得自己再去找一下你的公网ip。ddns的作用,就是把你的公网ip与一个域名死死绑定,无论ip怎么变,你都可以通过域名去访问到之前的服务

    校验提示文案

    提交
    收起所有回复
  • 青龙不行吗

    校验提示文案

    提交
    青龙当然可以,不过环境依赖的问题确实比较烦人。这个相对简单一点

    校验提示文案

    提交
    收起所有回复
  • 你好,我用的威联通的212p3,因为自带的ddns不稳定,也想用docker搞一个ddnsgo的方法,但是docker里搜索不到ddnsgo等,所以想请教一下,您这个可以参照的安装吗?

    校验提示文案

    提交
    如果可以连上ssh的,可以通过这种方式来进行安装

    校验提示文案

    提交
    收起所有回复
  • 为了方便值友们的使用,因为机制问题,源码在评论里附上,希望大家使用愉快!链接:去看看
    提取码:e4n5
    --来自百度网盘超级会员V8的分享

    校验提示文案

    提交
提示信息

取消
确认
评论举报

相关好价推荐
查看更多好价

相关文章推荐

更多精彩文章
更多精彩文章
天猫超级红包
距结束::
每天领现金,最高24888元
红包按钮
最新文章 热门文章
94
扫一下,分享更方便,购买更轻松