ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

使用Python和Digital Ocean创建和设置服务器

2023-07-28 18:23:02  阅读:261  来源: 互联网

标签:Python Digital Ocean 服务器


  • 通过Paramiko库与ssh进行编程交互
  • 使用Inquirer创建交互式命令行工具
  • 通过API在Digital Ocean上创建服务器(或Droplet)
  • 在Python中阅读YAML
  • 从python启动终端命令

先进行一点设计和设置

我们需要从什么开始?要连接到DigitalOcean API,我们首先需要一个令牌。您可以在这里生成一个,或者:

  • 从数字海洋仪表板,单击API链接
  • 点击生成新令牌
  • 为令牌选择一个名称
  • 选择读写功能
  • 点击生成令牌
  • 立即复制生成的令牌
  • 将其粘贴到您的项目文件夹中,并带有自定义名称的新env.yaml文件中,在这里我们使用doAuthToken

接下来你需要的是sshKey。如果您已经在DigitalOcean上上传了任何指纹,您可以使用它;在列表sshKeys下复制env.yaml文件中的指纹。
否则,创建一个新的sshKey并将其添加到Digital Ocean中。如果您不知道如何生成sshKey或如何将其上传到您的数字海洋团队,您可以在这里找到所有信息
我们还需要安装一些软件包,因此请运行以下命令:

pip install requests paramiko inquirer yaml

现在我们有了我们需要的东西,让我们开始代码吧!

第一个请求

要开始使用Digital Ocean的API,我们可以调用一些简单的端点,稍后在Droplet创建步骤中需要这些端点:分发和大小端点。
我们必须将之前创建的令牌添加到我们的请求标头中,以便DO的端点正常工作。
由于我们将经常使用此标头,我们最好编写一个函数来处理它:

#utils.py
def buildBasicHeaders():
    configsFile = yaml.safe_load(open('./env.yaml'))
    token = configsFile['configs']['doAuthToken']
    headers = {'Content-Type':'application/json','Authorization':'Bearer '+token}
    return headers

标头构建器完成后,我们现在可以请求发行版列表:

#utils.py
def getDistributions(distribution=""):
  url = "https://api.digitalocean.com/v2/images?type=distribution"
  headers = buildBasicHeaders()
  response = requests.get(url,headers=headers)
  images = response.json()['images']
  images = list(filter(lambda i: i['status'] == 'available', images))

  return images

有了这个功能,我们需要从DO端点为我们的服务器提供所有可能的分布。虽然如此,它们并不总是都可用,因此我们过滤结果以仅包含可用发行版的列表。我们现在可以要求液滴的可用尺寸。

#utils.py
def getSizes():
  url = "https://api.digitalocean.com/v2/sizes"
  headers = buildBasicHeaders()
  response = requests.get(url,headers=headers)
  return response.json()['sizes']

它与前一个相似,但更直接,所以我们可以继续前进。我们首先创建了这些函数,因为它们是创建droplet所需的参数,但您可以在构建步骤中设置更多配置。您可以在这里查看可能的参数。

创建脚本的第一行

现在让我们创建一个createServer.py文件,该文件将为我们的程序提供主要进程。
由于我们将向用户提出一堆问题,我们将使用查询库。
让我们轻松开始:

#createServer.py
import utils
import inquirer

questions = [
     inquirer.Text('machineName', message="Pick a name for your machine")
]

answers = inquirer.prompt(questions)
machineName = answers['machineName']

我们首先要求用户为新创建的droplet命名。
Questions变量将是我们向用户提出的所有问题的数组。用这条线

answers = inquirer.prompt(questions)

我们告诉Inquirer向用户询问列表中的所有问题,并将结果保存在answers中,这将是一个列表,作为键,每个提示的第一个参数(在这种情况下,machineName)提供值。

既然我们已经掌握了这一点,我们就可以得到我们的规模和分布。这有点复杂,但我会一步一步地解释。

#createServer.py
#....
sizes = utils.getSizes()
sizeChoices = []
for i,size in enumerate(sizes, start=1):
    choice = f"[{i}] RAM: {size['memory']}MB, CPUs: {size['vcpus']}, disk: {size['disk']}GB"
     sizeChoices.append(choice)

images = utils.getDistributions()
imageChoices = []
for i,image in enumerate(images, start=1):
    choice = f"[{i}] {image['description']}"
    imageChoices.append(choice)

questions = [
    inquirer.Text('machineName', message="Pick a name for your machine"),  
    inquirer.List('dropletSize', message="What size do you need?", choices=sizeChoices ),
    inquirer.List('dropletImage', message="What OS do you prefer?", choices=imageChoices)
]


answers = inquirer.prompt(questions)
machineName = answers['machineName']

index = sizeChoices.index(answers['dropletSize'])
dropletSize = sizes[index]['slug']

index = imageChoices.index(answers['dropletImage'])
dropletImage = images[index]['id']

让我们退后一步,了解一下发生了什么,好吗?

第一件事:选项列表创建:


sizes = utils.getSizes()
sizeChoices = []
for i,size in enumerate(sizes, start=1):
    choice = f"[{i}] RAM: {size['memory']}MB, CPUs: {size['vcpus']}, disk: {size['disk']}GB"
    sizeChoices.append(choice)

images = utils.getDistributions()
imageChoices = []
for i,image in enumerate(images, start=1):
    choice = f"[{i}] {image['description']}"
    imageChoices.append(choice)

对于尺寸和图像,我们需要先枚举它们,这样我们就可以循环浏览图像,并有一个参考索引供以后参考。
在我们有了一系列选择后,我们可以将这些其他选择添加到用户Questions中。


questions = [
    inquirer.Text('machineName', message="Pick a name for your machine"),  
    inquirer.List('dropletSize', message="What size do you need?", choices=sizeChoices ),
    inquirer.List('dropletImage', message="What OS do you prefer?", choices=imageChoices)
]

answers = inquirer.prompt(questions)

与之前关于机器名称的问题一样,inquirer.List问题类型需要一个键(如dropletSizedropletImage)和向用户显示的问题。此外,我们必须提供一份选择清单,即我们以前准备的清单。
在这一点上,如果我们执行命令,我们应该有这样的东西:

 

显示迄今为止预期结果的GIF

 

这是一个好的开始;你觉得呢?
让我们快速解释一下上述代码的最后一部分:

#....

index = sizeChoices.index(answers['dropletSize'])
dropletSize = sizes[index]['slug']


index = imageChoices.index(answers['dropletImage'])
dropletImage = images[index]['id']

在这里,我们有点黑客攻击。由于Inquirer只返回所选答案的文本,我们正在选择列表中找到它的索引,以在原始列表中获取它。之后,我们检索创建液滴所需的部件,因此尺寸的弹头和图像的ID。
现在有趣的部分来了!

创建液滴

终于是时候创建我们的液滴了!

#utils.py
def createDroplet(name, size, image):
    headers = buildBasicHeaders()
    get_droplets_url = "https://api.digitalocean.com/v2/droplets"
    configsFile = yaml.safe_load(open('./env.yaml'))
    keys = configsFile['configs']['sshKeys']
    keys = getConfig('sshKeys')
    data = {
      'name':name,
      'size':size,
      'image':int(image),
      'ssh_keys': keys
    }
    response = requests.post(get_droplets_url, headers=headers,json=data)
    return response.json()['droplet']

这一切都非常简单,所以我将介绍关于sshKeys的几点:

  • 数据中的sshKeys参数可以包含一个值列表:这些是我们在DigitalOcean上拥有的密钥,我们希望放在新的droplet上,使用它们而不是user:password身份验证通过ssh进行连接。
  • 在我们的YAML中,sshKeys参数将是可以从DigitalOcean sshKeys面板中提取的指纹列表

话虽如此,在返回createServer.py之前,我们知道我们可能想让我们的droplet来检查其状态,所以让我们也为此编写一个函数。

#utils.py
def getDroplet(dropletId):
    headers = buildBasicHeaders()
    get_droplets_url = f"https://api.digitalocean.com/v2/droplets/{dropletId}"
    response = requests.get(get_droplets_url, headers=headers)
    return response.json()['droplet']

好的,让我们使用我们的新功能来创建我们的液滴!

#createServer.py
newDroplet  = utils.createDroplet(machineName,dropletSize,dropletImage)

newDroplet = utils.getDroplet(newDroplet['id'])
print('[*] Creating the droplet... ', end='', flush=True)
while newDroplet['status'] != 'active' :
    newDroplet = utils.getDroplet(newDroplet['id'])
    time.sleep(1)
print('OK')
print('[*] Powering the new droplet on...', end='', flush=True)
time.sleep(60)  
print('Droplet ready')

那么,这里发生了什么?

  1. 我们用我们的createDroplet函数创建一个Droplet
  2. 一旦我们创建了新的droplet并获得了其id,我们就会请求检查状态(肯定尚未active
  3. 我们告诉用户我们正在创建droplet,然后向服务器迭代请求,直到它显示droplet处于活动状态;我们可以向用户反馈droplet已创建
  4. 现在,我们必须等到液滴开机后才能操作它。恭喜!现在你有一个全新的液滴要处理!

通过SSH连接并安装软件包

最后,我们可以通过ssh连接,自动安装一些软件包:是时候介绍paramiko了!

#createServer.py
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ip = newDroplet['networks']['v4'][0]['ip_address']
configsFile = yaml.safe_load(open('./env.yaml'))
path = configsFile['configs']['localKeyFile']
ssh.connect(ip, username='root',key_filename=path)
print('CONNECTED')
commands = [
        "apt-get update",
        "apt-get install -y apache2",
        # add all the commands you'd like to exec
]

for command in commands:
  ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(command)
  print(ssh_stdout.read().decode())
ssh_stdin.close()

好吧,再说一遍,这里发生了什么?让我们更深入地看看它!

ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

首先,多亏了paramiko,我们正在创建一个sshClient实例。这是接下来所有行动的中心。
之后,我们将在系统上自动进行ssh密钥搜索。在这两行中,paramiko从我们机器的默认位置加载密钥,如果我们不提供任何精确的密钥,则设置默认回退密钥(我们连接时仍然会这样做)

ip = newDroplet['networks']['v4'][0]['ip_address']
configsFile = yaml.safe_load(open('./env.yaml'))
path = configsFile['configs']['localKeyFile']
ssh.connect(ip, username='root',key_filename=path)
print('CONNECTED')

在这里,我们得到了Droplet的ip以及用于连接的所需私钥的路径;之后,我们可以使用thesshssh.connect()通过ssh进行连接。现在我们可以执行我们想要的操作:

commands = [
        "apt-get update",
        "apt-get install -y apache2",
        # add all the commands you'd like to exec
]

for command in commands:
  ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(command)
  print(ssh_stdout.read().decode())
ssh_stdin.close()

我们列出了要执行的命令:之后,我们通过它们循环;ssh.exec_command(command)方法允许我们执行命令并在ssh_stdout变量中接收输出,我们将在屏幕上打印该变量以遵循该过程。
当所有命令执行后,我们可以关闭连接。

最终获得控制权

现在滴已经准备就绪,软件包已经安装完毕,我们想登录shell并检查apache是否已正确安装。因此,让我们通过添加最后几行来结束它:

#createServer.py
print(f"New machine is at IP: {ip}")
webbrowser.open(f'http://{ip}')
os.system(f"ssh -o StrictHostKeyChecking=no root@{ip}")

我们写下液滴的IP,以便我们知道它,并且我们可以注意,以防我们需要(您始终可以在您的数字海洋仪表板上找到此信息);然后我们打开一个新的浏览器窗口到该IP,然后直接在ssh上登录,在用于创建droplet的终端上!

标签:Python,Digital Ocean,服务器
来源:

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有