Atender a todas las cuestiones mencionadas demanda tiempo y esfuerzo que no dejan lugar para la investigación de nuevas tendencias, prácticas ágiles o automatización
Pareciera ser imposible que esto suceda, pero muchas organizaciones siguen gestionando sus desarrollos de esta forma
En este apartado veremos qué metodologías y/o herramientas han surgido para solucionar algunas de las necesidades mencionadas según la perspectiva de desarrollo e infraestructura
El término DevOps tiene varias interpretaciones por ser relativamente nuevo
y ciertamente amplio
Básicamente DevOps promueve:
Existen diversos productos que promueven IaC
![]() |
Chef |
![]() |
Puppet Labs |
![]() |
Ansible |
![]() |
SaltStack |
¿Cómo es posible garantizar un merge satisfactorio en todos los casos?
En este apartado veremos ejemplos de algunas herramientas que promueven la práctica DevOps, pero más importante aún, que simplifican tareas repetitivas y promueven el desempeño ágil de nuestra tarea
A remote server automation and deployment tool written in Ruby
role :demo, %w{srv-01 srv-02 srv-03}
task :uptime do
on roles(:demo), in: :parallel do |host|
uptime = capture(:uptime)
puts "#{host.hostname} reports: #{uptime}"
end
end
cap install # Inicializa el directorio
cap -T # Lista todas las posibles tareas disponibles
role :demo, %w{localhost}
server '33.33.33.10',
roles: %w(demo),
ssh_options: {
user: 'vagrant',
forward_agent: true,
auth_methods: %w(publickey password),
password: 'vagrant'
}
Veremos ejemplos de uso de capistrano deployando en un servidor virtual con IP 33.33.33.10
jekyll build
cap production deploy
jekyll build
cap production deploy:rollback
base_dir
├── current -> /opt/sites/jekyll/releases/20160619173257
├── releases
│ └── YYYYMMDDHHmmii
├── repo
└── shared
vagrant up
vagrant destroy
vagrant ssh
vagrant provision
vagrant reload [--provision]
vagrant box list
Esta funcionalidad permite iniciar varias VMs en un mismo Vagrantfile
permitiendo así simular ambientes complejos
shell provisioning
Vagrant.configure(2) do |config|
config.vm.box = "chef/ubuntu-14.04"
config.vm.box_check_update = false
config.vm.network "private_network", ip: "33.33.34.10"
config.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y apache2
SHELL
end
Multimachine (4 vms) con docker y shell provisioning
Vagrant.configure(2) do |config|
config.vm.define 'master', primary: true do |app|
app.vm.box = "chef/ubuntu-14.04"
app.vm.network "private_network", ip: "33.33.35.10"
app.vm.provision "docker" do |d|
...
end
end
(1..3).each do |num|
config.vm.define "node-#{num}" do |app|
app.vm.box = "chef/ubuntu-14.04"
app.vm.network "private_network", ip: "33.33.35.1#{num}"
app.vm.provision "docker" do |d|
...
end
end
end
AWS provider con Chef
Antes de poder utilizar este provider es necesario instalar el plugin que provee esta funcionalidad
vagrant plugin install vagrant-aws
# Se usa un box dummy
vagrant box add dummy \
https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
vagrant up --provider=aws
Vagrant.configure("2") do |config|
config.vm.box = "dummy"
config.vm.provider :aws do |aws,override|
aws.ami = "ami-7747d01e"
aws.access_key_id = ENV['AWS_ACCESS_KEY']
aws.secret_access_key = ENV['AWS_SECRET_KEY']
aws.keypair_name = 'car'
override.ssh.username = "ubuntu"
override.ssh.private_key_path = "#{ENV['HOME']}/.ssh/id_rsa"
end
config.vm.provision :chef_solo do |chef|
chef.run_list = [
'recipe[apt]',
'recipe[my_rancher]'
]
end
end
vagrant rsync
- Requiere este comando si algo se modifica -
Ejemplo de servidor Rancher
docker run -v ~/workspace/:/home/eclipse/workspace/ \
-e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:ro \
-d leesah/eclipse
docker search
docker images
docker pull
docker run
docker ps
docker diff
docker commit
docker inspect
docker log
Iniciamos una instancia de Mysql con docker
docker run -p 33060:3306 -e MYSQL_ROOT_PASSWORD=devops -d mysql:5.7
mysql -u root -h 127.0.0.1 --port 33060 -pdevops
¿Qué sucede si eliminamos el contenedor?
docker volume ls
docker volume create
docker volume rm
docker volume inspect
Se describe una aplicación compuesta por más de un contenedor mediante un yml
version: "2"
services:
wordpress:
image: wordpress
links:
- db:mysql
ports:
- 8080:80
db:
image: mysql:5.7
docker-compose up
docker-compose ps
docker-compose stop
docker-compose rm
docker-compose scale
Además, es posible realizar búsquedas sobre estas entidades
package 'nginx'
service 'nginx' do
action [:enable, :start]
end
template '/etc/nginx/sites-enabled/www.conf' do
source 'nginx-default.conf.erb'
variables(
server_name: 'www.mikroways.net',
document_root: '/var/www'
)
notifies :restart, 'service[nginx]', :immediately
end
Ver ejemplo completo
Es posible probar las recetas con una versión de chef llamada
chef-zero/chef-solo
rspec
rubocop
foodcritic
kitchen
# Crea/actualiza el rol web-server
knife role from file roles/web-server.rb
# Crea dos nodos llamados web-01 y web-02 en amazon con el rol
# web-server
knife ec2 server create -I ami-b1a652d1 -f m1.small --ssh-user ubuntu \
-N web-01 -r 'role[web-server]'
knife ec2 server create -I ami-b1a652d1 -f m1.small --ssh-user ubuntu \
-N web-02 -r 'role[web-server]'
## Listamos las instancias de Amazon EC2
knife ec2 server list
Algunos detalles que se omiten se toman de la configuración de knife
knife status
knife role list
knife node list
knife search '*:*'
knife search 'platform:ubuntu AND (name:web-01 OR role:web-server)'
knife ssh -x ubuntu 'role:web-server' sudo service nginx stop
knife exec -E 'search(:node, "role:web-server").each do |node|
puts(
node.name => {
ip: node.cloud.public_ipv4,
mem: node.memory.total,
cpu: node.cpu.total
}
)
end'
Lo interesante es que uno puede usar búsquedas en las recetas
Esta receta utiliza búsquedas para configurar los backends de haproxy
all_web_servers = search(:node, "role:web-server")
members = []
all_web_servers.each do |web|
members <<
{
"hostname" => web['cloud']['public_hostname'],
"ipaddress" => web['cloud']['public_ipv4'],
"port" => 80,
"ssl_port" => 80
}
end
node.default['haproxy']['members'] = members
include_recipe 'haproxy'
knife ec2 server create -I ami-b1a652d1 -f m1.small --ssh-user ubuntu \
-N proxy -r 'recipe[myhaproxy]'
Probar con curl y eliminar con
knife ec2 server delete <INSTANCE-ID> -P
chef_role 'web-server' do
run_list ["recipe[apt]","recipe[web-server]"]
end
machine_batch do
machine 'web-01' do
run_list ['role[web-server]']
end
machine 'web-02' do
run_list ['role[web-server]']
end
end
machine 'proxy' do
run_list ['recipe[myhaproxy]']
end
Corremos en nuestra PC
chef-client -z -r 'my-infra::chef,my-infra::aws,my-infra'
chef_role 'web-server' do
action :delete
end
machine_batch do
action :destroy
machines 'web-01', 'web-02', 'proxy'
end
Corremos en nuestra PC
chef-client -z -r 'my-infra::chef,my-infra::aws,my-infra::delete'
chef-client -z -r 'my-infra::chef,my-infra::vagrant,my-infra'
Esto es muy importante, porque sólo cambiando el driver de aprovisionamiento, podemos reusar nuestra infraestructura definida
Podemos incluso tener un cluster con VMs de diferentes proveedores
La alternativa a chef-provisioning
docker-compose.yml
rancher-compose up
rancher-compose up -u my-app
Contacto
contacto@mikroways.net
christian.rodriguez@mikroways.net
@car_unlp