Openstack - Básico
IaaS
Infraestrutura como Serviço, em inglês Infrastructure as a Service (IaaS) é um modelo de serviço no qual os recursos computacionais são fornecidos por um determinado provedor. Os fornecedores de IaaS fornecem muitos serviços como armazenamento, redes e virtualização liberando os consumidores do fardo de manter o hardware de uma infraestrutura localmente.
Os serviços de IaaS podem estar em uma nuvem pública (compartilhando o hardware com outros usuários), uma nuvem privada (sem compartilhamento de recursos) ou uma núvem híbrida, combinando os dois modelos.
Nesse tipo de serviço é comum existirem APIs para facilitar a criação de recursos de forma automatizada.
Openstack
Openstack é uma plataforma livre e de código aberto para computação em nuvem. É um dos três projetos de código aberto mais ativos do mundo, junto com o kernel do Linux e o navegador Chromium.
Assim como a maioria dos softwares livres, o Openstack é mantido por muitas empresas de forma simultânea, cada empresa possui sua própria versão derivada da versão “community” (chamada de upstream).
Algumas da empresas envolvidas no Openstack:
- Red Hat
- Oracle
- Mirantis
- Canonical
- IBM
- HP (deixou o projeto)
- SUSE (deixou o projeto)
Openstack Morreu?
Assim como os Mainframes, Cobol e Java, não o Openstack não está morrendo.
Casos de Uso
Componentes
Porque VMs e não Containers
Existem alguns casos em que máquinas virtuais são mais vantajosas que containeres:
- Persistência de dados ocorre em vários lugares;
- Fornecedor não suporta containers;
- Arquitetura diferente do CPU da máquina hospedeira;
- Maior isolamento;
- Teste de drivers específicos;
DevStack
https://www.openstack.org/software/project-navigator/deployment-tools
O DevStack é um conjunto de scripts utilizados para criar um ambiente completo de Openstack através do git. Este ambiente é muito mais leve e simples que uma instalação de produção, e normalmente é utilizado para testes e estudo.
Independente do tipo de instalação utilizado, se sua máquina possui menos de 16GB, habilite o swap.
Torne-se o usuário root:
sudo -i
Execute os seguintes comandos para criar o arquivo de swap, formatá-lo, habilitá-lo e configurá-lo para montagem automática:
dd if=/dev/zero of=/swapfile bs=1M count=4096
mkswap /swapfile
chmod 0600 /swapfile
swapon /swapfile
echo '/swapfile swap swap defaults 0 0' >> /etc/fstab
Configuração
Para a versão zed do Openstack, uma máquina com Ubuntu 22.04 foi utilizada.
Como o usuário root
, execute os seguintes comandos:
apt-get update && apt-get install -y git
useradd -s /bin/bash -d /opt/stack -m stack
chmod +x /opt/stack
echo "stack ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/stack
cat > /etc/systemd/system/devstack-reboot-fix.service <<'EOF'
[Unit]
Description=Sobe a bridge e configura o iptables
After=ovs-vswitchd.service
[Service]
Type=oneshot
ExecStart=ip link set br-ex up
ExecStart=ip addr add 172.24.4.1/24 dev br-ex
ExecStart=iptables -t nat -A POSTROUTING -j MASQUERADE -s 172.24.4.0/24
[Install]
WantedBy=multi-user.target
EOF
systemctl enable devstack-reboot-fix.service
sudo -u stack -i
Em uma instalação single-node
do DevStack temos uma infraestrutura básica e relativamente simples de provisionar. Recomenda-se 16GB para esse tipo de instalação.
Como o usuário stack
executar os seguintes comandos como base:
git clone -b stable/zed https://opendev.org/openstack/devstack
cd devstack
cat > local.conf <<'EOF'
[[local|localrc]]
ADMIN_PASSWORD=openstack
DATABASE_PASSWORD=$ADMIN_PASSWORD
RABBIT_PASSWORD=$ADMIN_PASSWORD
SERVICE_PASSWORD=$ADMIN_PASSWORD
enable_plugin heat https://opendev.org/openstack/heat stable/zed
enable_service s-proxy s-object s-container s-account
EOF
Instalação
Com o arquivo definido, iniciar a instalação:
./stack.sh
Ao finalizar a instalação, podemos começar a interagir com o Openstack através de variáveis de ambiente que são configuradas pelo arquivo openrc
:
source openrc
Problemas ao Reiniciar
Ao reiniciar a host do Devstack as máquinas virtuais ficarão sem acesso externo e também não poderemos acessá-las através do floating ip
. Um serviço chamado devstack-reboot-fix.service
foi criado para executar os seguintes comandos automaticamente após a inicialização do ovs-vswitchd
:
ip link set br-ex up
ip addr add 172.24.4.1/24 dev br-ex
iptables -t nat -A POSTROUTING -j MASQUERADE -s 172.24.4.0/24
Cliente (openstack) e Painel (Horizon)
Todos os serviços do Openstack possuem seus próprios clientes, cada qual com sua própria sintaxe. Felizmente existe um cliente unificado chamado openstack
que padroniza e centraliza a execução dos comandos que conversarão com os mais diversos componentes. Em algumas poucas exceções o cliente de determinados componentes precisarão ser utilizados (por exemplo a criação de “shares”).
O cliente do Openstack é bastante versátil e fornece uma sintaxe padronizada para a grande maioria dos comandos:
openstack <tipo> <ação> [parâmetros] [nome]
Por exemplo:
openstack image create --file ~/debian-11-genericcloud-amd64-20230124-1270.qcow2 debian-11
Caso tenha dúvida em algum comando, podemos verificar a saída da ajuda. Existem algumas formas e dependendo da versão a exibição pode ser diferente entre estes dois comandos:
openstack help server create
# ou
openstack server create --help
Para situações mais simples, podemos simplesmente omitir os parâmetros obrigatórios e receber uma saída útil para verificações:
openstack image create
# output:
# usage: openstack image create [-h] [-f {json,shell,table,value,yaml}] [-c COLUMN] [--noindent] [--prefix PREFIX] [--max-width <integer>] [--fit-width] [--print-empty] [--id <id>]
# [--container-format <container-format>] [--disk-format <disk-format>] [--min-disk <disk-gb>] [--min-ram <ram-mb>] [--file <file> | --volume <volume>]
# [--force] [--progress] [--sign-key-path <sign-key-path>] [--sign-cert-id <sign-cert-id>] [--protected | --unprotected]
# [--public | --private | --community | --shared] [--property <key=value>] [--tag <tag>] [--project <project>] [--import] [--project-domain <project-domain>]
# <image-name>
# openstack image create: error: the following arguments are required: <image-name>
O formato padrão de exibição das informações do Openstack é em tabela:
openstack image list
# output:
# +--------------------------------------+---------------------------------+--------+
# | ID | Name | Status |
# +--------------------------------------+---------------------------------+--------+
# | f05c04f2-1071-4e1f-b1c9-58f31f97c094 | Fedora-Cloud-Base-36-1.5.x86_64 | active |
# | 71bbd221-8517-4117-9eb9-e7741c0697ed | cirros-0.5.2-x86_64-disk | active |
# +--------------------------------------+---------------------------------+--------+
Podemos modificar o resultado trocando para JSON ou YAML, o que facilita o processamento destas informações por linguagens de programação:
openstack image list -f json
# output:
# [
# {
# "ID": "f05c04f2-1071-4e1f-b1c9-58f31f97c094",
# "Name": "Fedora-Cloud-Base-36-1.5.x86_64",
# "Status": "active"
# },
# {
# "ID": "71bbd221-8517-4117-9eb9-e7741c0697ed",
# "Name": "cirros-0.5.2-x86_64-disk",
# "Status": "active"
# }
# ]
Muitas vezes a saída dos comandos são muito longas e acabam sendo muito difíceis de ler, para isso podemos utilizar o subcomando --fit-width
ou --max-width=<N>
:
openstack image show f05c04f2-1071-4e1f-b1c9-58f31f97c094 --max-width=80
# +------------------+-----------------------------------------------------------+
# | Field | Value |
# +------------------+-----------------------------------------------------------+
# | checksum | 7f7cdad25b77f232078bf454c39529d3 |
# | container_format | bare |
# | created_at | 2023-02-25T01:04:26Z |
# | disk_format | qcow2 |
# | file | /v2/images/f05c04f2-1071-4e1f-b1c9-58f31f97c094/file |
# | id | f05c04f2-1071-4e1f-b1c9-58f31f97c094 |
# | min_disk | 0 |
# | min_ram | 0 |
# | name | Fedora-Cloud-Base-36-1.5.x86_64 |
# | owner | 35f37247834742cfb58946b13265e4a6 |
# | properties | hw_rng_model='virtio', os_hash_algo='sha512', os_hash_val |
# | | ue='e1b41fe4e7e911c58fc90cceb30da8adfb8302e5935f2edad8b11 |
# | | 72f1a52c6ba3faa1f23d170aeef1f062f77bf7838bc9e8a6dd3c58dfe |
# | | 7278596c4899338620', os_hidden='False', |
# | | owner_specified.openstack.md5='', |
# | | owner_specified.openstack.object='images/Fedora-Cloud- |
# | | Base-36-1.5.x86_64', owner_specified.openstack.sha256='' |
# | protected | False |
# | schema | /v2/schemas/image |
# | size | 448266240 |
# | status | active |
# | tags | |
# | updated_at | 2023-02-25T01:04:31Z |
# | virtual_size | 5368709120 |
# | visibility | public |
# +------------------+-----------------------------------------------------------+
Variáveis de Ambiente
Para interagir com o Openstack podemos especificar parâmetros no próprio cliente ou utilizar variáveis de ambiente, a segunda forma é muito mais comum. Após carregar as variáveis do arquivo openrc
podemos listá-las da seguinte forma no nosso ambiente:
env | grep OS_
# output:
# OS_PASSWORD=openstack
# OS_IDENTITY_API_VERSION=3
# OS_TENANT_NAME=demo
# OS_USER_DOMAIN_ID=default
# OS_REGION_NAME=RegionOne
# OS_AUTH_URL=http://10.42.0.15/identity
# OS_USERNAME=demo
# OS_AUTH_TYPE=password
# OS_PROJECT_NAME=demo
# OS_PROJECT_DOMAIN_ID=default
# OS_CACERT=
# OS_VOLUME_API_VERSION=3
Estas variáveis representam nosso usuário, a senha, o ponto de autenticação, o projeto padrão entre outras coisas. No nosso caso, apenas trocar o valor de OS_USERNAME
para admin
já nos torna administrador do Openstack, por exemplo:
openstack domain list
# output:
# You are not authorized to perform the requested action: identity:list_domains. (HTTP 403) (Request-ID: req-fba7f20a-ca8d-4aca-9a04-20bac073e265)
export OS_USERNAME=admin
openstack domain list
# output:
# <exibição dos domínios>
É uma boa prática criar arquivos de ambiente para cada usuário, ou mesmo para ambientes diferentes.
Domínios, projetos, usuários e permissões
O Openstack é uma plataforma que suporta multitenência, isso significa que os usuários podem utilizar sem correr o risco de colidir com os demais utilizadores. Para garantir essa separação lógica, o Openstack é divido entre domínios e projetos.
Podemos separar a hierarquia de segregação do Openstack da seguinte forma:
- Region
- Domain 1
- Project P1
- Project P2
- User A1
- User A2
- Domain 2
- Project P3
- Project P4
- User B1
- User B2
- Domain 1
A region padrão chama-se RegionOne serve apenas para separação lógica de clusters de Openstack.
Domain
O domain contém os projetos. Um domínio padrão chamado Default
é criado durante a instalação com usuários locais, recomenda-se que novos usuários sejam criados em outros domínios. Um domínio diferente do Default
pode ser conectado a algum gerenciador de identidade (LDAP, SSO) e fornecer uma forma mais robusta de autenticação.
openstack domain create d1
Project
O project contém todos os demais objetos como máquinas virtuais, redes, buckets, discos e etc.
openstack project create --domain d1 p1
User
openstack user create --domain d1 --password openstack operator1
Roles
Por padrão existem apenas duas roles que podemos utilizar no Openstack reconhecida por todos os serviços, member
e admin
. Adicionando um usuário como admin ele se torna administrador do cluster por completo e não somente do projeto ou domínio específico. A permissão do tipo member
permite a criação de redes, imagens, máquinas virtuais e outros serviços que estão dentro apenas dos projetos.
openstack role add --user operator1 --domain d1 admin
# openstack role add --user operator1 --domain d1 member
Para visualizar as permissões:
openstack role assignment list --names
Com o usuário criado podemos baixar seu arquivo de configuração pelo painel do Horizon ou criá-lo manualmente:
bash > operator1-d1.sh <<'EOF'
export OS_REGION_NAME=RegionOne
export OS_INTERFACE=public
export OS_AUTH_URL=http://10.42.0.15/identity
export OS_USERNAME=operator1
export OS_USER_DOMAIN_NAME=d1
export OS_PROJECT_NAME=p1
export OS_PASSWORD=openstack
export OS_IDENTITY_API_VERSION=3
export OS_PROJECT_ID=cda0e77a1b4b421c96075d6d1d77b2e5
export OS_PROJECT_DOMAIN_ID=35e96d353f39439fb944194ff14e08a3
export PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w(operator1-d1)\$ '
EOF
Para carregá-lo, basta executar:
source operator1-d1.sh
Redes
O serviço responsável pela criação e gerenciamento de redes é o Neutron.
Tenant e Provider
As redes tenant
são as redes privadas, podem ser criadas pelos usuários comuns e não afetam a rede física. Este tipo de rede possui sua própria máscara, seu servidor DHCP e etc. Já a rede do tipo provider
utiliza-se da rede física e dos serviços nela presente, como o próprio DHCP e os ips disponíveis para alocação.
Ao criar uma máquina virtual dentro de uma rede, normalmente a máquina já recebe um endereço IP, a não ser que a rede tenha sido configurada para não ter esse comportamento.
Criar uma rede
Uma rede do Openstack é composta de dois elementos o network
e ao menos uma subnet
. Para as redes internas, a maioria das informações como DHCP, DNS e CIDR estão na subnet:
openstack network create network1
Criar uma subrede
Toda subnet
faz referência a apenas uma network
:
openstack subnet create \
--subnet-range 172.27.11.0/24 \
--dns-nameserver 208.67.222.222 \
--dns-nameserver 208.67.220.220 \
--network network1 \
network1-subnet
Acesso a Internet
As redes internas do Openstack são isoladas por padrão. Para conectar as máquinas destas redes na internet precisamos de um roteador conectado a uma rede que consiga se comunicar com o exterior. No caso do DevStack
já existe um roteador chamado router1
conectado a rede public
para fazer essa funçõa.
openstack router add subnet router1 network1-subnet
Floating IP
Um floating ip
é uma forma de expor uma determinada máquina além da rede privada. Com o floating IP podemos acessar os serviços presentes nas máquinas virtuais de forma segura e controlada através de security group
.
openstack floating ip create public
openstack floating ip list
Security Group
Um security group
atua como um firewall para os servidores e outros serviços em uma rede. Por padrão, todo o tráfego de origem externa para uma máquina é bloqueado, e todo o tráfego de origem interna para fora é permitido. Com security group
podemos modificar esse comportamento e bloquear ou abrir portas especificas:
openstack security group rule list \
-c 'IP Protocol' -c Ethertype -c 'IP Range' \
-c 'Port Range' -c Direction -c 'Remote Security Group'
# output:
# +-------------+------+-----------+------------+-----------+-------------------------+
# | IP Protocol | Type | IP Range | Port Range | Direction | Remote Security Group |
# +-------------+------+-----------+------------+-----------+-------------------------+
# | None | IPv6 | ::/0 | | ingress | f66d79fd-b36d-476d-b149 |
# | tcp | IPv4 | 0.0.0.0/0 | 22:22 | ingress | None |
# | icmp | IPv4 | 0.0.0.0/0 | | ingress | None |
# | None | IPv4 | 0.0.0.0/0 | | ingress | f66d79fd-b36d-476d-b149 |
# | None | IPv6 | ::/0 | | egress | None |
# | None | IPv4 | 0.0.0.0/0 | | egress | None |
# +-------------+------+-----------+------------+-----------+-------------------------+
Um exemplo muito comum de regras é a liberação do SSH e do ICMP (ping):
openstack security group rule create --proto icmp --dst-port 0 default
openstack security group rule create --proto tcp --dst-port 22 default
Flavors
Flavors, ou sabores em português, são as configurações pré-definidas de máquinas que podemos escolher durante a criação de um servidor. O DevStack cria alguns flavors para nós:
openstack flavor list
# output:
# +---------------+-------+------+-----------+-------+-----------+
# | Name | RAM | Disk | Ephemeral | VCPUs | Is Public |
# +---------------+-------+------+-----------+-------+-----------+
# | m1.tiny | 512 | 1 | 0 | 1 | True |
# | m1.small | 2048 | 20 | 0 | 1 | True |
# | m1.medium | 4096 | 40 | 0 | 2 | True |
# | m1.large | 8192 | 80 | 0 | 4 | True |
# | m1.nano | 128 | 1 | 0 | 1 | True |
# | m1.xlarge | 16384 | 160 | 0 | 8 | True |
# | m1.heat_int | 512 | 10 | 0 | 1 | True |
# | m1.micro | 192 | 1 | 0 | 1 | True |
# | cirros256 | 256 | 1 | 0 | 1 | True |
# | ds512M | 512 | 5 | 0 | 1 | True |
# | ds1G | 1024 | 10 | 0 | 1 | True |
# | ds2G | 2048 | 10 | 0 | 2 | True |
# | ds4G | 4096 | 20 | 0 | 4 | True |
# | m1.heat_micro | 128 | 1 | 0 | 1 | True |
# +---------------+-------+------+-----------+-------+-----------+
Além das opções mais óbvias do flavor
como CPU, memória e disco, podemos especificar discos efêmeros extras e swap.
openstack flavor create --vcpus 1 --ram 1024 --disk 10 --swap 1 flavor1.small
Neste caso, as máquinas que utilizarem este flavor
, terão automaticamente 1GB de memória swap.
Images
O serviço responsável pela criação e gerenciamento de imagens é o Glance.
Podemos utilizar formatos de imagens variados dentro do Openstack, porém os mais comuns são raw
e qcow2
.
O formato raw
(cru) é ligeiramente mais performático, aloca todo o espaço necessário de uma vez e não possui nenhum tipo de processamento extra ao gravar os dados.
O formato qcow2
(QEMU Copy on Write 2) pode ser alocado dinamicamente, suporta compressão, snapshots e imagens de referência (cow), em compensação possui uma camada extra de processamento em relação ao raw
.
openstack image list
# output:
# +--------------------------------------+---------------------------------+--------+
# | ID | Name | Status |
# +--------------------------------------+---------------------------------+--------+
# | fa9a7be9-d33e-434a-9bcc-47dee86042ea | Fedora-Cloud-Base-36-1.5.x86_64 | active |
# | d6912fc8-c41d-4b44-aa9f-3101404a537f | cirros-0.5.2-x86_64-disk | active |
# +--------------------------------------+---------------------------------+--------+
Podemos encontrar imagens especificamente prontas para o Openstack em https://docs.openstack.org/image-guide/obtain-images.html ou mesmo baixar imagens genéricas para cloud.
Por exemplo, para adicionar uma imagem do Debian em nosso ambiente, devemos primeiro baixá-la:
DEBIAN_IMAGE=https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2
wget $DEBIAN_IMAGE -O debian-11-amd64.qcow2
Podemos verificar mais informações sobre a imagem com o comando qemu-img
:
qemu-img info debian-11-amd64.qcow2
# output:
# image: debian-11-amd64.qcow2
# file format: qcow2
# virtual size: 2 GiB (2147483648 bytes)
# disk size: 318 MiB
# cluster_size: 65536
# Format specific information:
# compat: 1.1
# compression type: zlib
# lazy refcounts: false
# refcount bits: 16
# corrupt: false
# extended l2: false
Note que o tamanho atual da imagem é 318 MiB, mas seu tamanho expendido é 2 GiB. A imagem está compactada.
Para subir a imagem para dentro do Openstack, executamos o seguinte comando:
openstack image create --file debian-11-amd64.qcow2 --disk-format qcow2 debian-11-amd64
Customização
As vezes faz sentido ter uma imagem com todas as definições pré-definidas. Isso ajuda na inicialização, já que a máquina não precisará se configurar. Essa velocidade e bastante útil nos casos em que as aplicações precisam escalar, e por isso é a forma padrão utilizada em contêineres.
Existem muitos comandos para customizar imagens no Linux, um deles é o virt-customize
presente no pacote guestfs-tools
. Podemos modificar a senha do root, instalar pacotes e outras coisas sem a necessidade de uma máquina virtual:
sudo virt-customize -a debian.qcow2 \
--root-password password:debian \
--install apache2,libapache2-mod-php
Máquinas Virtuais
O serviço responsável pela criação e gerenciamento de máquinas virtuais é o Nova.
Para criar uma máquina virtual devemos definir ao menos quatro parâmetros:
- Image
- Network
- Flavor
- Name
Um exemplo mais completo para a criação de máquina virtual seria o seguinte:
openstack server create \
--image cirros-0.5.2-x86_64-disk \
--network shablau \
--flavor m1.nano \
--user-data cloud-init.yml \
--key-name key \
cirros
User Data
O user data
são informações que podemos entregar para a máquina virtual executar algo durante a sua primeira inicialização. Podemos fornecer os mais variados tipos de scripts desde que a máquina virtual possa interpretá-los, exemplos muito comuns são shell script
e cloud-init
.
Scripts
Os scripts do user data podem ser escritos em qualquer linguagem de programação, desde que a máquina possa interpretá-lo. Exemplo interessantes são shell script, perl, python, lua, etc.
#!/bin/bash
echo fedora | passwd fedora --stdin
Cloud-init
O cloud-init contém instruções quase sempre descritivas sobre como deve ser o estado da máquina. Seu formato é chamado de YAML. Arquivos YAML possuem sintaxe própria e podem representar estruturas de dados assim como JSON.
#cloud-config
password: openstack
chpasswd: {expire: False}
package_update: true
packages:
- apache2
- mariadb-server
runcmd:
- systemctl enable --now mysql apache2
Volumes
O serviço responsável pela criação e gerenciamento de volumes é o Cinder.
Quando criamos uma máquina no Openstack sem nenhum parâmetro específico de disco a máquina recebe um disco efêmero. Os discos efêmeros são destruidos juntamente com a máquina virtual.
Podemos criar um volume com o seguinte comando:
openstack volume create --size 10 mysql
Também é possível criar um volume baseado em uma imagem, e assim ter um disco de boot maior que o tamanho já definido. No exemplo abaixo criamos um volume baseado na imagem do cirros, mas aumentamos o volume para 5GB:
openstack volume create --image cirros-0.5.2-x86_64-disk --size 5 cirros-persistent
Para listar os volumes utilizamos openstack volume list
, o campo Attached to
quando preenchido, mostra em qual máquina o disco está, isso modifica o campo Status
para in-use ao invés de available.
openstack volume list
# output:
# +-------------------------+--------+-----------+------+---------------------------------+
# | ID | Name | Status | Size | Attached to |
# +-------------------------+--------+-----------+------+---------------------------------+
# | 29f9f70f-125e-441f-920d | cirros | available | 5 | |
# | b68b9e2e-25fe-49f3-96d9 | mysql | in-use | 10 | Attached to cirros on /dev/vdb |
# +-------------------------+--------+-----------+------+---------------------------------+
Podemos adiconar um volume em uma máquina virtual criada com o seguinte comando:
openstack server add volume cirros mysql
# output:
# +-----------------------+-------------------------+
# | Field | Value |
# +-----------------------+-------------------------+
# | ID | b68b9e2e-25fe-49f3-96d9 |
# | Server ID | 3c92963b-3e5c-4760-8076 |
# | Volume ID | b68b9e2e-25fe-49f3-96d9 |
# | Device | /dev/vdb |
# | Delete On Termination | False |
# +-----------------------+-------------------------+
Para criar uma máquina vitual com um disco persistente, basta referenciá-lo durante a criação ao invés de uma imagem:
openstack server create --volume cirros --flavor m1.micro --network private cirros
Object Storage
Por padrão o Ceph utiliza o Swift como object storage (também conhecido como “bucket”), capaz de armazenar petabytes de dados de forma escalável e redundante. O swift possui seu próprio protocolo mas também é relativamente compatível com S3.
O swift chama o local de armazenamento dos arquivos de “container” apesar do nome “bucket” ser mais comum, tratando-se deste storage estes termos são intercambiáveis.
openstack container create configurations
cat > ports.conf <<EOF
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf
Listen 80
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
EOF
openstack object create configurations ports.conf
openstack object list configurations
cd /tmp
openstack object save configurations ports.conf
cat ports.conf
Utilizando o curl
Utilizar o curl
para fazer consultas e baixar arquivos do Swift é relativamente simples e facilita bastante a utilização de arquivos de configuração externos às máquinas. Além da consulta podemos executar todas as operações que normalmente faríamos através do cliente openstack
, como enviar e deletar arquivos.
Para isso precisaremos:
- Criar um token
- Obter a “conta” do bucket
- Descobrir o endereço do swift
- Executar o
curl
com o cabeçalhoX-Auth-Token
openstack token issue
# output:
# +------------+-----------------------------------------------------------------+
# | Field | Value |
# +------------+-----------------------------------------------------------------+
# | expires | 2023-02-26T04:11:31+0000 |
# | id | gAAAAABj- |
# | | s3jQorDC4WTsxCu6Pr375PGy5RNRwZPmTVZyzzCvtL5mWImRbXmkkl6Hs-dCgq0 |
# | | vEdczLdAw1Amjie903PgLPEW_YZ0c- |
# | | 8kiNLbbQbRgsm6j2Au06Vve6sSxddYLFwCoqSt1liIIe3bFTocUfBksazyafge2 |
# | | UYVbtdeMoOdXuFdRVU |
# | project_id | a20a6ced757e4c0f9b7048154654d9fe |
# | user_id | 80b554bf14b24e25806094b3810f4ec8 |
# +------------+-----------------------------------------------------------------+
Copiar o token e salvar em uma variável para melhor conveniência, o token não possui quebras de linhas.
export TOKEN='gAAAAABj...2OnQ77POMschrNk'
Obter a conta do bucket:
openstack container show configurations
# output:
# +----------------+---------------------------------------+
# | Field | Value |
# +----------------+---------------------------------------+
# | account | AUTH_a20a6ced757e4c0f9b7048154654d9fe |
# | bytes_used | 334 |
# | container | configurations |
# | object_count | 1 |
# | storage_policy | Policy-0 |
# +----------------+---------------------------------------+
Normalmente o swift possui um endereço como swift.openstack.example.com
o que torna a utilização muito mais fácil, mas em alguns para acessar o swift necessitaremos de um endereço IP e uma porta, como é o caso do DevStack. Para descobrir onde o swift está, basta verificarmos os endpoints
do Openstack:
openstack endpoint list -c 'Service Name' -c 'Service Type' -c URL
# output:
# +--------------+----------------+-----------------------------------------------+
# | Service Name | Service Type | URL |
# +--------------+----------------+-----------------------------------------------+
# | glance | image | http://10.42.0.15/image |
# | placement | placement | http://10.42.0.15/placement |
# | nova_legacy | compute_legacy | http://10.42.0.15/compute/v2/$(project_id)s |
# | cinder | block-storage | http://10.42.0.15/volume/v3/$(project_id)s |
# | swift | object-store | http://10.42.0.15:8080/v1/AUTH_$(project_id)s |
# | heat-cfn | cloudformation | http://10.42.0.15/heat-api-cfn/v1 |
# | nova | compute | http://10.42.0.15/compute/v2.1 |
# | heat | orchestration | http://10.42.0.15/heat-api/v1/$(project_id)s |
# | cinderv3 | volumev3 | http://10.42.0.15/volume/v3/$(project_id)s |
# | neutron | network | http://10.42.0.15:9696/networking |
# | swift | object-store | http://10.42.0.15:8080 |
# | keystone | identity | http://10.42.0.15/identity |
# +--------------+----------------+-----------------------------------------------+
Um exemplo de listagem e download de arquivo através do curl:
curl -H "X-Auth-Token: $TOKEN" http://10.42.0.15:8080/v1/AUTH_a20a6ced757e4c0f9b7048154654d9fe
# configurations
curl -H "X-Auth-Token: $TOKEN" http://10.42.0.15:8080/v1/AUTH_a20a6ced757e4c0f9b7048154654d9fe/configurations
# ports.conf
Heat
O Heat é o serviço de orquestração do Openstack que funciona de forma declarativa. Através do Heat podemos definir templates de nossas aplicações, conhecido como Heat Orchestration Template ou HOT.
- https://docs.openstack.org/heat/latest/
- https://docs.openstack.org/heat/zed/template_guide/openstack.html
Uma stack é considerada como uma unidade, podemos consultar o estado de cada objeto separadamente e atualizá-los de forma isolada, sem impactar os outros elementos.
Abaixo temos um exemplo de um exemplo de uma stack que instala um server
com apache, faz algumas customizações na inicialização e configura um security group
:
heat_template_version: wallaby
description: Servidor Apache
parameters:
image:
type: string
description: imagem do webserver
default: debian-11-amd64
key:
type: string
description: chave ssh para acessar o webserver
text:
type: string
description: texto para aparecer no servidor
default: '<h1>IaaS</h1>'
resources:
apache_security_group:
type: OS::Neutron::SecurityGroup
properties:
rules:
- { direction: ingress, protocol: icmp }
- { direction: ingress, protocol: tcp, port_range_min: 22, port_range_max: 22 }
- { direction: ingress, protocol: tcp, port_range_min: 80, port_range_max: 80 }
- { direction: ingress, protocol: tcp, port_range_min: 443, port_range_max: 443 }
apache:
type: OS::Nova::Server
properties:
flavor: m1.micro
networks:
- network: private
image: { get_param: image }
key_name: { get_param: key }
security_groups:
- get_resource: apache_security_group
user_data:
str_replace:
template: |
#!/bin/bash
apt-get update && apt-get install -y apache2
echo '$text' > /var/www/html/index.html
params:
$text: { get_param: text }
Para aplicar a stack precisamos acessar o arquivo de alguma forma, o arquivo pode ser local ou estar em algum endereço:
openstack stack create --template apache.yml apache --parameter key=mit
Assim que criarmos a stack, podemos consultar o estado de cada elemento da stack:
openstack stack resource list apache
# output:
# +-----------------------+-------------------------+----------------------------+-----------------+----------------------+
# | resource_name | physical_resource_id | resource_type | resource_status | updated_time |
# +-----------------------+-------------------------+----------------------------+-----------------+----------------------+
# | apache | 4e7c3cd7-ada4-475c-9c45 | OS::Nova::Server | CREATE_COMPLETE | 2023-03-12T14:44:17Z |
# | apache_security_group | 36ecafff-b653-401f-af49 | OS::Neutron::SecurityGroup | CREATE_COMPLETE | 2023-03-12T14:44:17Z |
# +-----------------------+-------------------------+----------------------------+-----------------+----------------------+
Uma vez que a stack esteja completa, podemos simplesmente atualizá-la:
openstack stack update \
--template apache.yml apache \
--parameter key=mit \
--parameter text='<h1>Openstack!</h1>'
Se listarmos os recursos, veremos que apenas o servidor foi atualizado:
openstack stack resource list apache
# output:
# +-----------------------+-------------------------+----------------------------+-----------------+----------------------+
# | resource_name | physical_resource_id | resource_type | resource_status | updated_time |
# +-----------------------+-------------------------+----------------------------+-----------------+----------------------+
# | apache_security_group | 570707af-c3c2-4a91-959a | OS::Neutron::SecurityGroup | CREATE_COMPLETE | 2023-03-12T14:46:01Z |
# | apache | a3c34634-b7b6-423b-885e | OS::Nova::Server | CREATE_COMPLETE | 2023-03-12T14:49:13Z |
# +-----------------------+-------------------------+----------------------------+-----------------+----------------------+