ホームページ > バックエンド開発 > Python チュートリアル > Terraform と Ansible を使用した KVM 上の Flask と PostgreSQL のデプロイメントの自動化

Terraform と Ansible を使用した KVM 上の Flask と PostgreSQL のデプロイメントの自動化

DDD
リリース: 2025-01-02 14:49:42
オリジナル
951 人が閲覧しました

?イントロ

こんにちは、この投稿では、Terraform で Libvirt を使用して 2 つの KVM をローカルにプロビジョニングし、その後、Ansible を使用して Flask アプリと PostgreSQL をデプロイします。

コンテンツ

  • プロジェクトのアーキテクチャ
  • 要件
  • KVM の作成
  • Ansible プレイブックの作成
    • Docker をインストールするためのプレイブック
    • postgresql をインストールして構成するためのプレイブック
    • Flask アプリをデプロイするためのプレイブック
    • プレイブックとテストを実行する
  • 結論

?プロジェクトのアーキテクチャ

そこで、Terraform を使用して 2 つの VM を作成し、Ansible を使用して Flask プロジェクトとデータベースをデプロイします。

Automating Deployment of Flask and PostgreSQL on KVM with Terraform and Ansible

?要件

このプロジェクトでは OS として Ubuntu 22.04 LTS を使用しました。別の OS を使用している場合は、必要な依存関係をインストールするときに必要な調整を行ってください。

このセットアップの主な前提条件は、KVM ハイパーバイザーです。したがって、システムに KVM をインストールする必要があります。 Ubuntu を使用している場合は、次の手順を実行できます:

sudo apt -y install bridge-utils cpu-checker libvirt-clients libvirt-daemon qemu qemu-kvm
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

次のコマンドを実行して、プロセッサが仮想化機能をサポートしていることを確認します。

$ kvm-ok

INFO: /dev/kvm exists
KVM acceleration can be used
ログイン後にコピー
ログイン後にコピー

Terraform をインストールする

$ wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
$ sudo apt update && sudo apt install terraform -y
ログイン後にコピー
ログイン後にコピー

インストールを確認します:

$ terraform version

Terraform v1.9.8
on linux_amd64
ログイン後にコピー
ログイン後にコピー

Ansible をインストールする

$ sudo apt update
$ sudo apt install software-properties-common
$ sudo add-apt-repository --yes --update ppa:ansible/ansible
$ sudo apt install ansible -y
ログイン後にコピー
ログイン後にコピー

インストールを確認します:

$ ansible --version

ansible [core 2.15.1]
...
ログイン後にコピー
ログイン後にコピー

KVMの作成

Terraform で libvirt プロバイダーを使用して、KVM 仮想マシンをデプロイします。

main.tf を作成し、使用するプロバイダーとバージョンを指定するだけです:

terraform {
  required_providers {
    libvirt = {
      source = "dmacvicar/libvirt"
      version = "0.8.1"
    }
  }
}

provider "libvirt" {
  uri = "qemu:///system"
}

ログイン後にコピー
ログイン後にコピー

その後、terraform init コマンドを実行して環境を初期化します。

$ terraform init

Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/template from the dependency lock file
- Reusing previous version of dmacvicar/libvirt from the dependency lock file
- Reusing previous version of hashicorp/null from the dependency lock file
- Using previously-installed hashicorp/template v2.2.0
- Using previously-installed dmacvicar/libvirt v0.8.1
- Using previously-installed hashicorp/null v3.2.3

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
ログイン後にコピー
ログイン後にコピー

次に、variables.tf を作成します。この variables.tf ファイルは、libvirt ディスク プール パス、VM の OS としての Ubuntu 20.04 イメージ URL、および VM ホスト名のリストの入力を定義します。

variable "libvirt_disk_path" {
  description = "path for libvirt pool"
  default     = "default"
}

variable "ubuntu_20_img_url" {
  description = "ubuntu 20.04 image"
  default     = "https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.img"
}

variable "vm_hostnames" {
  description = "List of VM hostnames"
  default     = ["vm1", "vm2"]
}
ログイン後にコピー
ログイン後にコピー

main.tf を更新しましょう:

resource "null_resource" "cache_image" {
  provisioner "local-exec" {
    command = "wget -O /tmp/ubuntu-20.04.qcow2 ${var.ubuntu_20_img_url}"
  }
}

resource "libvirt_volume" "base" {
  name   = "base.qcow2"
  source = "/tmp/ubuntu-20.04.qcow2"
  pool   = var.libvirt_disk_path
  format = "qcow2"
  depends_on = [null_resource.cache_image]
}
# Volume for VM with size 10GB
resource "libvirt_volume" "ubuntu20-qcow2" {
  count          = length(var.vm_hostnames)
  name           = "ubuntu20-${count.index}.qcow2"
  base_volume_id = libvirt_volume.base.id
  pool           = var.libvirt_disk_path
  size           = 10737418240  # 10GB
}

data "template_file" "user_data" {
  count    = length(var.vm_hostnames)
  template = file("${path.module}/config/cloud_init.yml")
}

data "template_file" "network_config" {
  count    = length(var.vm_hostnames)
  template = file("${path.module}/config/network_config.yml")
}

resource "libvirt_cloudinit_disk" "commoninit" {
  count          = length(var.vm_hostnames)
  name           = "commoninit-${count.index}.iso"
  user_data      = data.template_file.user_data[count.index].rendered
  network_config = data.template_file.network_config[count.index].rendered
  pool           = var.libvirt_disk_path
}

resource "libvirt_domain" "domain-ubuntu" {
  count  = length(var.vm_hostnames)
  name   = var.vm_hostnames[count.index]
  memory = "1024" # VM memory
  vcpu   = 1 # VM CPU

  cloudinit = libvirt_cloudinit_disk.commoninit[count.index].id

  network_interface {
    network_name   = "default"
    wait_for_lease = true
    hostname       = var.vm_hostnames[count.index]
  }

  console {
    type        = "pty"
    target_port = "0"
    target_type = "serial"
  }

  console {
    type        = "pty"
    target_type = "virtio"
    target_port = "1"
  }

  disk {
    volume_id = libvirt_volume.ubuntu20-qcow2[count.index].id
  }

  graphics {
    type        = "spice"
    listen_type = "address"
    autoport    = true
  }
}
ログイン後にコピー
ログイン後にコピー

スクリプトは、Libvirt プロバイダーを使用して複数の KVM VM をプロビジョニングします。 Ubuntu 20.04 の基本イメージをダウンロードし、VM ごとにクローンを作成し、ユーザーおよびネットワーク設定用に Cloud-init を構成し、指定されたホスト名、1GB メモリ、および SPICE グラフィックスを備えた VM をデプロイします。セットアップは、var.vm_hostnames.

で指定されたホスト名の数に基づいて動的に適応します。

前述したように、私はcloud-initを使用しているので、configディレクトリの下にネットワーク構成とcloud initをセットアップしましょう:

mkdir config/
ログイン後にコピー
ログイン後にコピー

次に、config/cloud_init.yml を作成します。構成内で ssh アクセス用の公開 ssh キーを必ず設定してください。

#cloud-config
runcmd:
  - sed -i '/PermitRootLogin/d' /etc/ssh/sshd_config
  - echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
  - systemctl restart sshd
ssh_pwauth: true
disable_root: false
chpasswd:
  list: |
    root:cloudy24
  expire: false
users:
  - name: ubuntu
    gecos: ubuntu
    groups:
      - sudo
    sudo:
      - ALL=(ALL) NOPASSWD:ALL
    home: /home/ubuntu
    shell: /bin/bash
    lock_passwd: false
    ssh_authorized_keys:
      - ssh-rsa AAAA...
ログイン後にコピー
ログイン後にコピー

次に、config/network_config.yml のネットワーク構成:

version: 2
ethernets:
  ens3:
    dhcp4: true
ログイン後にコピー
ログイン後にコピー

プロジェクトの構造は次のようになります:

sudo apt -y install bridge-utils cpu-checker libvirt-clients libvirt-daemon qemu qemu-kvm
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

次に、計画を実行して、何が行われるかを確認します。

$ kvm-ok

INFO: /dev/kvm exists
KVM acceleration can be used
ログイン後にコピー
ログイン後にコピー

そして、terraform apply を実行してデプロイメントを実行します。

$ wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
$ sudo apt update && sudo apt install terraform -y
ログイン後にコピー
ログイン後にコピー

virsh コマンドを使用して VM の作成を確認します:

$ terraform version

Terraform v1.9.8
on linux_amd64
ログイン後にコピー
ログイン後にコピー

インスタンスの IP アドレスを取得します:

$ sudo apt update
$ sudo apt install software-properties-common
$ sudo add-apt-repository --yes --update ppa:ansible/ansible
$ sudo apt install ansible -y
ログイン後にコピー
ログイン後にコピー

ubuntu ユーザーを使用して VM にアクセスしてみます:

$ ansible --version

ansible [core 2.15.1]
...
ログイン後にコピー
ログイン後にコピー

Ansible プレイブックの作成

次に、Docker に Flask と Postgresql をデプロイするための Ansible Playbook を作成しましょう。まず、ansible ディレクトリと ansible.cfg ファイルを作成する必要があります:

terraform {
  required_providers {
    libvirt = {
      source = "dmacvicar/libvirt"
      version = "0.8.1"
    }
  }
}

provider "libvirt" {
  uri = "qemu:///system"
}

ログイン後にコピー
ログイン後にコピー
$ terraform init

Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/template from the dependency lock file
- Reusing previous version of dmacvicar/libvirt from the dependency lock file
- Reusing previous version of hashicorp/null from the dependency lock file
- Using previously-installed hashicorp/template v2.2.0
- Using previously-installed dmacvicar/libvirt v0.8.1
- Using previously-installed hashicorp/null v3.2.3

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
ログイン後にコピー
ログイン後にコピー

次に、hosts という名前のインベントリ ファイルを作成します。

variable "libvirt_disk_path" {
  description = "path for libvirt pool"
  default     = "default"
}

variable "ubuntu_20_img_url" {
  description = "ubuntu 20.04 image"
  default     = "https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.img"
}

variable "vm_hostnames" {
  description = "List of VM hostnames"
  default     = ["vm1", "vm2"]
}
ログイン後にコピー
ログイン後にコピー

ansible ping コマンドを使用して VM を確認しています:

resource "null_resource" "cache_image" {
  provisioner "local-exec" {
    command = "wget -O /tmp/ubuntu-20.04.qcow2 ${var.ubuntu_20_img_url}"
  }
}

resource "libvirt_volume" "base" {
  name   = "base.qcow2"
  source = "/tmp/ubuntu-20.04.qcow2"
  pool   = var.libvirt_disk_path
  format = "qcow2"
  depends_on = [null_resource.cache_image]
}
# Volume for VM with size 10GB
resource "libvirt_volume" "ubuntu20-qcow2" {
  count          = length(var.vm_hostnames)
  name           = "ubuntu20-${count.index}.qcow2"
  base_volume_id = libvirt_volume.base.id
  pool           = var.libvirt_disk_path
  size           = 10737418240  # 10GB
}

data "template_file" "user_data" {
  count    = length(var.vm_hostnames)
  template = file("${path.module}/config/cloud_init.yml")
}

data "template_file" "network_config" {
  count    = length(var.vm_hostnames)
  template = file("${path.module}/config/network_config.yml")
}

resource "libvirt_cloudinit_disk" "commoninit" {
  count          = length(var.vm_hostnames)
  name           = "commoninit-${count.index}.iso"
  user_data      = data.template_file.user_data[count.index].rendered
  network_config = data.template_file.network_config[count.index].rendered
  pool           = var.libvirt_disk_path
}

resource "libvirt_domain" "domain-ubuntu" {
  count  = length(var.vm_hostnames)
  name   = var.vm_hostnames[count.index]
  memory = "1024" # VM memory
  vcpu   = 1 # VM CPU

  cloudinit = libvirt_cloudinit_disk.commoninit[count.index].id

  network_interface {
    network_name   = "default"
    wait_for_lease = true
    hostname       = var.vm_hostnames[count.index]
  }

  console {
    type        = "pty"
    target_port = "0"
    target_type = "serial"
  }

  console {
    type        = "pty"
    target_type = "virtio"
    target_port = "1"
  }

  disk {
    volume_id = libvirt_volume.ubuntu20-qcow2[count.index].id
  }

  graphics {
    type        = "spice"
    listen_type = "address"
    autoport    = true
  }
}
ログイン後にコピー
ログイン後にコピー

ここで、playbook.yml とロールを作成します。この Playbook は、Docker、Flask、PostgreSQL をインストールして構成します。

mkdir config/
ログイン後にコピー
ログイン後にコピー

Docker をインストールするためのプレイブック

次に、roles/docker という名前の新しいディレクトリを作成します。

#cloud-config
runcmd:
  - sed -i '/PermitRootLogin/d' /etc/ssh/sshd_config
  - echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
  - systemctl restart sshd
ssh_pwauth: true
disable_root: false
chpasswd:
  list: |
    root:cloudy24
  expire: false
users:
  - name: ubuntu
    gecos: ubuntu
    groups:
      - sudo
    sudo:
      - ALL=(ALL) NOPASSWD:ALL
    home: /home/ubuntu
    shell: /bin/bash
    lock_passwd: false
    ssh_authorized_keys:
      - ssh-rsa AAAA...
ログイン後にコピー
ログイン後にコピー

docker に task という名前の新しいディレクトリを作成し、新しいファイル main.yml を作成します。このファイルは Docker と Docker Compose をインストールします:

version: 2
ethernets:
  ens3:
    dhcp4: true
ログイン後にコピー
ログイン後にコピー
$ tree
.
├── config
│   ├── cloud_init.yml
│   └── network_config.yml
├── main.tf
└── variables.tf
ログイン後にコピー

postgresql をインストールして構成するための Playbook

次に、psql という新しいディレクトリを作成し、vars、tempalates、tasks というサブディレクトリを作成します。

$  terraform plan

data.template_file.user_data[1]: Reading...
data.template_file.user_data[0]: Reading...
data.template_file.network_config[1]: Reading...
data.template_file.network_config[0]: Reading...
...

Plan: 8 to add, 0 to change, 0 to destroy
ログイン後にコピー

その後、vars 内に main.yml を作成します。これらは、ユーザー名、パスワードなどの設定に使用される変数です:

$ terraform apply

...
null_resource.cache_image: Creation complete after 10m36s [id=4239391010009470471]
libvirt_volume.base: Creating...
libvirt_volume.base: Creation complete after 3s [id=/var/lib/libvirt/images/base.qcow2]
libvirt_volume.ubuntu20-qcow2[1]: Creating...
libvirt_volume.ubuntu20-qcow2[0]: Creating...
libvirt_volume.ubuntu20-qcow2[1]: Creation complete after 0s [id=/var/lib/libvirt/images/ubuntu20-1.qcow2]
libvirt_volume.ubuntu20-qcow2[0]: Creation complete after 0s [id=/var/lib/libvirt/images/ubuntu20-0.qcow2]
libvirt_domain.domain-ubuntu[1]: Creating...
...

libvirt_domain.domain-ubuntu[1]: Creation complete after 51s [id=6221f782-48b7-49a4-9eb9-fc92970f06a2]

Apply complete! Resources: 8 added, 0 changed, 0 destroyed
ログイン後にコピー

次に、docker-compose.yml.j2 という jinja ファイルを作成します。このファイルを使用して、postgresql コンテナを作成します:

$ virsh list

 Id   Name   State
----------------------
 1    vm1    running
 2    vm2    running
ログイン後にコピー

次に、タスクに main.yml を作成します。そこで、 docker-compose.yml.j2 をコピーし、 docker compose を使用して実行します:

$ virsh net-dhcp-leases --network default

Expiry Time           MAC address         Protocol   IP address          Hostname   Client ID or DUID
-----------------------------------------------------------------------------------------------------------------------------------------------
2024-12-09 19:50:00   52:54:00:2e:0e:86   ipv4       192.168.122.19/24   vm1        ff:b5:5e:67:ff:00:02:00:00:ab:11:b0:43:6a:d8:bc:16:30:0d
2024-12-09 19:50:00   52:54:00:86:d4:ca   ipv4       192.168.122.15/24   vm2        ff:b5:5e:67:ff:00:02:00:00:ab:11:39:24:8c:4a:7e:6a:dd:78
ログイン後にコピー

Flask アプリをデプロイするためのプレイブック

まず、flask というディレクトリを作成し、次にサブディレクトリを再度作成する必要があります。

$ ssh ubuntu@192.168.122.15

The authenticity of host '192.168.122.15 (192.168.122.15)' can't be established.
ED25519 key fingerprint is SHA256:Y20zaCcrlOZvPTP+/qLLHc7vJIOca7QjTinsz9Bj6sk.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.122.15' (ED25519) to the list of known hosts.
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-200-generic x86_64)
...

ubuntu@ubuntu:~$
ログイン後にコピー

次に、main.yml を vars に追加します。このファイルは、以前に posgtresql 変数を参照し、さらに VM2(データベース VM) の IP アドレスを追加しました:

$ mkdir ansible && cd ansible
ログイン後にコピー

次に、テンプレートに config.py.j2 を作成します。このファイルは、Flask プロジェクトの古い構成ファイルを置き換えます:

[defaults]
inventory = hosts
host_key_checking = True
deprecation_warnings = False
collections = ansible.posix, community.general, community.postgresql
ログイン後にコピー

次に、テンプレートに docker-compose.yml.j2 を作成します。このファイルを使用して、docker compose を使用してコンテナーを作成します:

[vm1]
192.168.122.19 ansible_user=ubuntu

[vm2]
192.168.122.15 ansible_user=ubuntu
ログイン後にコピー

次にタスク内にmain.ymlを作成します。このファイルを使用して、Flask プロジェクトのクローンを作成し、compose ファイルを追加し、config.py を置き換え、docker compose を使用して新しいコンテナを作成します:

$ ansible -m ping all

192.168.122.15 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
192.168.122.19 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
ログイン後にコピー

プロジェクトの構造は次のようになります:

---
- name: Deploy Flask
  hosts: vm1
  become: true
  remote_user: ubuntu
  roles:
    - flask
    - config

- name: Deploy Postgresql
  hosts: vm2
  become: true
  remote_user: ubuntu
  roles:
    - psql
    - config
ログイン後にコピー

Playbook とテストを実行する

最後に、ansible-playbook を実行して PostgreSQL と Flask をデプロイしましょう:

$ mkdir roles
$ mkdir docker
ログイン後にコピー

完了したら、エラーがないことを確認してください。すると、2 つ作成されていることがわかります。 VM1 は Flask で、VM2 は Postgresql です:

sudo apt -y install bridge-utils cpu-checker libvirt-clients libvirt-daemon qemu qemu-kvm
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ブラウザを使用してアプリにアクセスしてみます。http://:

と入力してください。

Automating Deployment of Flask and PostgreSQL on KVM with Terraform and Ansible

新しいタスクを追加しようとすると、データがデータベースに追加されます:

Automating Deployment of Flask and PostgreSQL on KVM with Terraform and Ansible

結論

最後に、この記事を読んでいただきありがとうございます。ご質問、ご提案、フィードバックがございましたら、お気軽にコメントを残してください。

注意: プロジェクト リポジトリ: danielcristho/that-i-write

以上がTerraform と Ansible を使用した KVM 上の Flask と PostgreSQL のデプロイメントの自動化の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート