编程语言
首页 > 编程语言> > 使用Python和Digital Ocean创建和设置服务器

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

作者:互联网

先进行一点设计和设置

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

接下来你需要的是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的几点:

话虽如此,在返回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,服务器
来源: