Nesta seção, criaremos tarefas para inicializar o ambiente do servidor, como criar um usuário de manutenção, definir uma senha para o usuário inicial e definir o nome de host do servidor ao fazer login em uma instância EC2 recém-criada no Capistrano pela primeira vez via SSH.
Antes disso, tentei várias formas de adicionar nomes de host, mas achei que seria mais inteligente marcar o lado EC2 ao definir HOSTS para cada instância após o primeiro login SSH, mas achei mais inteligente primeiro anexar uma tag que fosse a fonte do nome de host ao criar uma instância, e depois consultar essa tag e definir o nome HOST após fazer login em cada instância. Especialmente quando você quer colocar um número sequencial no nome do host ao configurar várias instâncias ao mesmo tempo, era fácil porque você podia reutilizar o número do contador usando a variável contador 'ec2.instances.create()'. Então, a forma de adicionar tags ao criar uma instância é
# Informações da Tag
Set :host_name, 'Deploy-Client'
~(Omitido)~
created_instances = []
Cnt = 0
enquanto cnt < fetch(:instance_count) do
i = ec2.instances.create(
~(中略)~
)
sleep 10 while i.status == :panding
i.tags['Name'] = [ fetch(:host_name), format("%02d", cnt+1) ].join('-')
created_instances < i.id
cnt += 1
end
~(省略)~
── と、ec2.instances.create()の後でタグを付けてやればOKです1。 Nesse caso, usaremos o valor dessa tag 'Nome' como nome host da instância em tarefas subsequentes.
De repente, eu perdi um erro, mas voltei ao tema principal. Como tarefa para o primeiro SSH, uso a tarefa 'init' que criei da última vez. O fluxo é criar um par de chaves para o usuário recém-criado no servidor de implantação, fazer login por SSH com o usuário padrão e então criar uma nova conta de usuário para manutenção. Depois disso, as configurações de SSH são feitas para o usuário usando autenticação de chave pública, uma senha é definida para o usuário padrão para desprivatizar os privilégios do sudo, e um nome de host é definido para sair uma vez. Primeiro, vários parâmetros são definidos antes de configurar a tarefa.
# Informações da Tag
Set :host_name, 'Deploy-Client'
# Conta de Usuário de Manutenção
Definir :user_account, 'Deploy-User'
Definir :user_password, 'senha'
# Senha inicial do usuário
defina :d ef_password, 'PalavraPassa'
# Obrigado a rodar sudo após o SSH
Configurado :p Obrigado, verdade
E então há a tarefa 'init' para a configuração inicial.
desc 'Verifique o status de ativação das novas instâncias'
tarefa :verificar fazer
created_instances_list = 'CREATED_INSTANCES'
run_locally
ec2 = AWS::EC2.new
AWS.memoize faz
início
If testar "[ -f ~/#{created_instances_list} ]"
created_instances = capture("cd ~; cat #{created_instances_list}").chomp
ci = created_instances.gsub(/(\[|\s|\])/, '').split(',')
target_instances = ec2.instances.select { |i| i.exists? && i.status == :executando && ci.include?( i.id) }.map(&:p rivate_ip_address)
se target_instances.comprimento == 0 então
raise "Nenhuma instância criada"
fim
pkfn = fetch(:p rivate_key_file)
target_instances.each { |var|
Server var, User: 'EC2-User', Roles: %W{Web App}, ssh_options: { Keys: %W(/home/deploy-user/#{pkfn}), forward_agent: true }
}
fim
resgate => e
info e
Saída
fim
fim
fim
fim
tarefa :init => :check fazer
run_locally
# Criar um par de chaves para autenticação de chave pública
target_dir = '~/.ssh'
if !test "[ -f #{target_dir}/#{fetch(:user_account)}_rsa ]"
if !test "[ -d #{target_dir} ]"
execute "mkdir -m 700 #{target_dir}"
fim
execute "cd #{target_dir}; ssh-keygen -t rsa -N \"\" -f #{target_dir}/#{fetch(:user_account)}_rsa"
fim
Set :p UBLIC_key_content, capture("cat #{target_dir}/#{fetch(:user_account)}_rsa.pub").chomp
Set :new_private_key_path, "#{target_dir}/#{fetch(:user_account)}_rsa"
fim
Sobre papéis(:web) fazer
# Configuração inicial (crie automaticamente contêineres .ssh ao criar usuários)
if !test "[ -d /etc/skel/.ssh/ ]"
executar:sudo, "mkdir -m 700 /etc/skel/.ssh/; sudo touch /etc/skel/.ssh/authorized_keys; sudo chmod 600 /etc/skel/.ssh/authorized_keys"
fim
# Criar um novo usuário para manutenção
is_user = capture(:sudo, "cut -d: -f1 /etc/passwd").chomp.gsub(/(\r\n)/, ',').split(',')
se !is_user.include? (fetch(:user_account)) então
execute :sudo, "useradd -G wheel #{fetch(:user_account)}"
execute :sudo, "echo \"#{fetch(:user_account)}:#{fetch(:user_password)}\" | sudo chpasswd"
fim
# Conceder privilégios SSH a novos usuários com autenticação de chave pública
auth_keys = "/home/#{fetch(:user_account)}/.ssh/authorized_keys"
se capture(:sudo, "cat #{auth_keys}").chomp != fetch(:p oblic_key_content) então
execute :sudo, "echo \"#{fetch(:p UBLIC_key_content)}\" | sudo tee #{auth_keys}"
fim
# Mude o nome de host da nova instância
ec2 = AWS::EC2.new
AWS.memoize faz
current_private_ip = capture(:sudo, "ifconfig | grep 'inet addr' | cut -d ':' -f 2 | awk 'NR==1 { print $1 }'").chomp
instance_ids = ec2.instances.select { |i| i.exists? && i.status == :running && i.private_ip_address == current_private_ip }.map(&:id)
host_basename = ec2.instances[instance_ids[0]].tags['Name']
se capture(:sudo, "hostname").chomp != host_basename.chomp então
executar:sudo, "echo \"#{host_basename}\" | sudo tee /proc/sys/kernel/hostname"
execute :sudo, "sed -i 's/\\(^HOSTNAME=\\).*/\\1#{host_basename}/' /etc/sysconfig/network"
execute :sudo, "nome do host #{host_basename}"
fim
fim
# Defina uma senha para o usuário padrão "ec2-user" e remova os privilégios do sudo
# Conceder privilégios sudo a novos usuários para manutenção
is_passwd = captura(:sudo, "corte -d: -f1,2 /etc/sombra").chomp.gsub(/(\r\n)/, ',').split(',')
se is_passwd.include? ("ec2-user:!!") então
execute :sudo, "echo \"ec2-user:#{fetch(:d ef_password)}\" | sudo chpasswd"
fim
execute :sudo, "sed -i s/ec2-user/#{fetch(:user_account)}/g /etc/sudoers.d/cloud-init"
fim
fim
Não, eu tinha muito conhecimento sobre Capistrano, Ruby e DSL, então foi bem difícil. Eu era bastante viciado em usar múltiplos comandos 'sudo' (redirecionamentos e pipes) para conectá-los. Por exemplo, no caso de uma cadeia de uma linha com comando pipe, por exemplo, 'execute :sudo, "mkdir ~/new_dir | chmod a+w ~/new_dir'', o subsequente 'chmod' da cadeia não tinha autoridade sudo, e apenas 'mkdir' era executado, então 'execute :sudo, "mkdir ~/new_dir | sudo chmod a+w ~/new_dir' funcionava bem. Além disso, o processo de adicionar saída padrão a um arquivo usando redirecionamentos '>' ou '>>' foi um erro e não funcionou, e foi necessário encadeá-lo com um pipe com comandos como 'chpasswd' ou 'tee' que pudesse captar a saída padrão. Além disso, nessas tarefas 'check' e 'init', fiz uma anotação usando o método 'AWS.memoize' para que, se houver cache para a resposta usando a API no 'AWS SDK for Ruby' (veja este site para detalhes). Ao fazer essa memorização, a resposta da API é armazenada em cache na tarefa 'check', então o desempenho da tarefa subsequente de 'init' é extremamente rápido.
Agora, vamos tentar executar a tarefa.
Lançamento de teste de $cap
INFO[a8c8eba0] Rodando /usr/bin/env eco -n ["i-e66952e0", "i-054a901c"] > ~/CREATED_INSTANCES no localhost
INFO[a8c8eba0] Terminou em 0,003 segundos com status de saída 0 (bem-sucedido).
Teste de $cap init
INFO[d38e8171] Rodando /usr/bin/env sudo mkdir -m 700 /etc/skel/.ssh/; sudo touch /etc/skel/.ssh/authorized_keys; sudo chmod 600 /etc/skel/.ssh/authorized_keys em 176.34.62.171
INFO[d38e8171] Terminou em 0,045 segundos com status de saída 0 (bem-sucedido).
INFO[84cb8ae3] Rodando /usr/bin/env sudo useradd -G wheel deploy-user em 176.34.62.171
INFO[ef747c5e] Rodando /usr/bin/env sudo mkdir -m 700 /etc/skel/.ssh/; sudo touch /etc/skel/.ssh/authorized_keys; sudo chmod 600 /etc/skel/.ssh/authorized_keys em 176.34.61.82
INFO[84cb8ae3] Terminou em 0,346 segundos com status de saída 0 (bem-sucedido).
INFO[235d5728] Rodando /usr/bin/env sudo echo "deploy-user:password" | sudo chpasswd em 176.34.62.171
INFO[ef747c5e] Terminou em 0,085 segundos com status de saída 0 (bem-sucedido).
INFO[82ead8fe] Rodando /usr/bin/env sudo useradd -G wheel deploy-user em 176.34.61.82
INFO[82ead8fe] Terminou em 0,073 segundos com status de saída 0 (bem-sucedido).
INFO[3fd263c2] Rodando /usr/bin/env sudo echo "deploy-user:password" | sudo chpasswd em 176.34.61.82
INFO[235d5728] Terminou em 0,163 segundos com status de saída 0 (bem-sucedido).
INFO[ad2ae489] Running /usr/bin/env sudo echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgQ31X0qXm/eHXZCIecjv57C66cZ4ikLdprDhHZs+KV5/vK0B+/47cZCXaT7UEHdI+Bm3jNTPJoRE8iPzkWB9L5Ks13tB7yJ5DGEIbFRe8d3kTa6Uwrj1HpL+i8hSZ7Bzbc4JvF5YULj97NNfVAmpNvAqxF1mRWeuzcmevnsVNJ1nF6ePysNjiWmboepWl+MvIJ8xXLYPzrw8mO1kg7WEB0QxqGN5OsVZjjbmEMLliJ+xbOGfxI50FEa+k2445Y3nynBD9krx/1wayurEVn2t8jKWDn6XLSUJ41Ep43QkwFibwtcVBsfDSPIHVm6S3k9RzaAQWpN6qSrUiabk0yAOp deploy-user@devlab-deploy01" | sudo tee /home/deploy-user/.ssh/authorized_keys em 176.34.62.171
INFO[3fd263c2] Terminou em 0,117 segundos com status de saída 0 (bem-sucedido).
INFO[ad2ae489] Terminou em 0,037 segundos com status de saída 0 (bem-sucedido).
INFO[36d81321] Running /usr/bin/env sudo echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgQ31X0qXm/eHXZCIecjv57C66cZ4ikLdprDhHZs+KV5/vK0B+/47cZCXaT7UEHdI+Bm3jNTPJoRE8iPzkWB9L5Ks13tB7yJ5DGEIbFRe8d3kTa6Uwrj1HpL+i8hSZ7Bzbc4JvF5YULj97Ks13tB7yJ5DGEIbFRe8d3kTa6Uwrj1HpL+i8hSZ7Bzbc4JvF5YULj977NfVAmpNvAqxF1mRWeuzcmevnsVNJ1nF6ePysNjiWmboepWl+MvIJ8xXLYPzrw8mO1kg7WEB0QxqGN5OsVZjjbmEMLliJ+xbOGfxI50FEa+k2445Y3nynBD9krx/1wayurEVn2t8jKWDn6XLSUJ41Ep43QkwFibwtcVBsfDSPIHVm6S3k9RzaAQWpN6qSrUiabk0yAOp deploy-user@devlab-deploy01" | sudo tee /home/deploy-user/.ssh/authorized_keys em 176.34.61.82
INFO[36d81321] Terminou em 0,044 segundos com status de saída 0 (bem-sucedido).
INFO[29ccb02a] Rodando /usr/bin/env sudo echo "deploy-client-01" | sudo tee /proc/sys/kernel/hostname em 176.34.61.82
INFO[29ccb02a] Terminou em 0,021 segundos com status de saída 0 (bem-sucedido).
INFO[5af43785] Rodando /usr/bin/env sudo sed -i 's/\(^HOSTNAME=\).*/\1deploy-client-01/' /etc/sysconfig/network em 176.34.61.82
INFO[5af43785] Terminou em 0,015 segundos com status de saída 0 (bem-sucedido).
INFO[17c7a3cc] Rodando /usr/bin/env sudo nome de host deploy-client-01 em 176.34.61.82
INFO[17c7a3cc] Terminou em 0,015 segundos com status de saída 0 (bem-sucedido).
INFO[1a64d176] Rodando /usr/bin/env sudo echo "ec2-user:PassWord" | sudo chpasswd em 176.34.61.82
INFO[1a64d176] Terminou em 0,031 segundos com status de saída 0 (bem-sucedido).
INFO[13f0fbe3] Rodando /usr/bin/env sudo sed -i s/ec2-user/deploy-user/g /etc/sudoers.d/cloud-init em 176.34.61.82
INFO[13f0fbe3] Terminado em 0,015 segundos com status de saída 0 (bem-sucedido).
INFO[23a6c3a5] Rodando /usr/bin/env sudo echo "deploy-client-02" | sudo tee /proc/sys/kernel/hostname em 176.34.62.171
INFO[23a6c3a5] Terminou em 0,043 segundos com status de saída 0 (bem-sucedido).
INFO[d0215821] Rodando /usr/bin/env sudo sed -i 's/\(^HOSTNAME=\).*/\1deploy-client-02/' /etc/sysconfig/network em 176.34.62.171
INFO[d0215821] Terminou em 0,018 segundos com status de saída 0 (bem-sucedido).
INFO[ce6a2993] Rodando /usr/bin/env sudo nome de host deploy-client-02 em 176.34.62.171
INFO[ce6a2993] Terminou em 0,017 segundos com status de saída 0 (bem-sucedido).
INFO[071e7b50] Rodando /usr/bin/env sudo echo "ec2-user:PassWord" | sudo chpasswd em 176.34.62.171
INFO[071e7b50] Terminou em 0,085 segundos com status de saída 0 (bem-sucedido).
INFO[28396919] Rodando /usr/bin/env sudo sed -i s/ec2-user/deploy-user/g /etc/sudoers.d/cloud-init on 176.34.62.171
INFO[28396919] Terminou em 0,018 segundos com status de saída 0 (bem-sucedido).
A implantação foi bem-sucedida. Para confirmar, entre por SSH com o novo usuário de manutenção criado a partir da linha de comando.
$ ssh -i ~/.ssh/deploy-user_rsa deploy-user@176.34.61.82
__| __|_ )
_| ( / Amazon Linux AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-ami/2014.03-release-notes/
8 pacotes(s) necessário(s) para segurança, de um total de 18 disponíveis
Execute o "sudo yum update" para aplicar todas as atualizações.
[deploy-user@deploy-client-01 ~]$ sudo su -
[root@deploy-client-01 ~]# Su ec2-user
[ec2-user@deploy-client-01 root]$ sudo su -
Confiamos que você recebeu a palestra habitual do Sistema local
Administrador. Geralmente, tudo se resume a estas três coisas:
#1) Respeitar a privacidade dos outros.
#2) Pense antes de digitar.
#3) Com grande poder vem grande responsabilidade.
senha [sudo] para usuário EC2:
EC2-User não está no arquivo do sudoers. Este incidente será reportado.
[ec2-user@deploy-client-01 root]$
Consegui fazer login com segurança. Além disso, o usuário de manutenção pode usar sudo sem senha, enquanto o usuário padrão, ec2-user, foi destituído dos privilégios sudo. A implantação está como esperado.
No entanto, há um pequeno problema com essa configuração de implantação, mesmo que o estado da instância após o lançamento da tarefa da instância seja ':running' e ela tenha sido iniciada, mas se as verificações de status estiverem no estado ':initializing', a tarefa de init para no meio sem conseguir fazer SSH pela primeira vez. Isso é um problema porque a tarefa de verificação atual só verifica se o Estado da Instância está :running ou não.
Está ficando mais longo, então vou parar por aqui por agora. Da próxima vez, vou tentar modificar a tarefa de verificação que determina as Verificações de Status, e como um processamento pós-processamento dessa tarefa de iniciação, vou escrever as configurações de SSH do usuário de manutenção recém-criado no arquivo de configuração do Capistrano, e finalmente introduzir o processo original de implantação para atualizar o pacote.
Site de referência
- A tag 'Name' também é usada como nome da lista de instâncias no AWS Management Console, então recomendamos adicionar essa tag para facilitar a identificação da instância que você criou. ↩