Essayez d'exécuter SlackBot réalisé avec Ruby x Sinatra sur AWS Lambda

Configuration à viser dans cet article

Untitled Diagram(1).png

① Exécutez une action spécifique dans Slack. (* Commande Slash cette fois) (2) Démarrez Lambda via API Gateway. ③ Exécutez la fonction placée dans Lambda et renvoyez les informations.

slackbot(2).gif

↑ Cela ressemble à une image d'opération. Cette fois, je vais déplacer SlackBot qui renvoie la température actuelle d'une certaine zone.

Public cible

--Les personnes qui veulent faire un simple SlackBot --Les personnes qui souhaitent toucher Lambda sur AWS

Qu'est-ce que Lambda?

AWS Lambda est un service informatique qui vous permet d'exécuter du code sans avoir à provisionner ou gérer un serveur. AWS Lambda exécute le code uniquement lorsque cela est nécessaire et passe automatiquement de quelques demandes par jour à des milliers de demandes par seconde. Vous ne payez que pour le temps de calcul que vous utilisez, sans frais sauf si le code est en cours d'exécution. AWS Lambda vous permet d'exécuter virtuellement du code dans n'importe quelle application ou service back-end sans aucune gestion requise. AWS Lambda exécute le code sur une infrastructure informatique hautement disponible et gère toutes vos ressources informatiques, y compris les serveurs et les systèmes d'exploitation, la maintenance du système, le provisionnement de la capacité et l'autoscaling, la surveillance du code et la journalisation. Éxécuter. Tout ce que vous avez à faire est de spécifier le code dans l'une des langues prises en charge par AWS Lambda. (Citation: document officiel d'Amazon)

Il est difficile de comprendre si c'est juste cela, mais le fait est que vous n'avez pas besoin d'un serveur pour exécuter le programme.

Normalement, si vous souhaitez exécuter une sorte de programme, l'achat d'un serveur et l'installation de divers middlewares prennent beaucoup de temps, mais dans Lambda, AWS gère tout cela, donc les développeurs Il semble que vous n'ayez qu'à vous concentrer sur la création du code source.

Avantages de l'utilisation de Lambda

Dans le cas d'un SlackBot comme celui-ci, je pense qu'il est juste d'utiliser Lambda car il n'a pas besoin de fonctionner tout le temps, mais uniquement lorsque c'est nécessaire.

Si l'implémentation est aussi légère que SlackBot, la méthode de déploiement utilisant Heroku, etc. est standard, mais j'ai envie d'utiliser AWS de nos jours.

spécification

Langue: Ruby2.5 Cadre: Sinatra Infrastructure: AWS Lambda

Formulaire rempli: slack-bot-on-aws-lambda

Créer SlackBot

Tout d'abord, créez le SlackBot essentiel.

Créer un annuaire

$ mkdir slack-bot-on-aws-lambda
$ cd slack-bot-on-aws-lambda

Spécifier la version de Ruby

# 2.N'importe quelle série 5 est OK
$ rbenv local 2.5.1 

Installez Sinatra

$ bundle init

Générez un Gemfile avec la commande ↑ et éditez-le comme suit.

./Gemfile


# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'sinatra'

Ensuite, installez Gem.

$ bundle install --path vendor/bundle

Pour vérifier le fonctionnement, je vais implémenter une page qui renvoie "Hello World!" Pour le moment.

$ touch main.rb

ruby:./main.rb


require 'sinatra'

get '/' do
  'Hello World!'
end

Après cela, démarrez Sinatra.

$ bundle exec ruby main.rb

[2020-09-21 20:47:35] INFO  WEBrick 1.4.2
[2020-09-21 20:47:35] INFO  ruby 2.5.1 (2018-03-29) [x86_64-darwin19]
== Sinatra (v2.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2020-09-21 20:47:35] INFO  WEBrick::HTTPServer#start: pid=50418 port=4567

Par défaut, Sinatra fonctionne sur le numéro de port "4567", alors accédez à "[localhost: 4567](localhost: 4567)".

スクリーンショット 2020-09-21 20.50.33.png

Succès si "Hello World!" Est affiché.

Implémentation d'un programme qui renvoie des informations météorologiques

Nous allons implémenter un programme qui renvoie des informations météorologiques, qui est la fonction principale du SlackBot créé cette fois.

Obtenir la clé API OpenWeather

https://openweathermap.org/ スクリーンショット 2020-09-21 20.54.33.png

Inscrivez-vous en tant que membre sur le site ci-dessus et obtenez une clé API.

スクリーンショット 2020-09-21 20.59.28_censored.jpg

Bien que le service soit rédigé en anglais, une explication détaillée est omise car il peut être exploité intuitivement dans une certaine mesure. Si vous ne comprenez vraiment pas, vous pouvez obtenir autant d'articles que vous le souhaitez par Google.

Installez diverses gemmes

Puisqu'il y a des gemmes nécessaires pour un traitement futur, installez-les immédiatement à ce moment.

./Gemfile


gem 'faraday'
gem 'rack'
gem 'rack-contrib'
gem 'rubysl-base64'
gem 'slack-ruby-bot'

N'oubliez pas de "bundle installer".

$ bundle install --path vendor/bundle

Créez src / weather.rb

$ mkdir src
$ touch src/weather.rb

Créez src / weather.rb et écrivez comme suit.

ruby:./src/weather.rb


require 'json'

class Weather
  def current_temp(locate)
    end_point_url = 'http://api.openweathermap.org/data/2.5/weather'
    api_key = #Clé d'API OpenWeather obtenue précédemment

    res = Faraday.get(end_point_url + "?q=#{locate},jp&APPID=#{api_key}")
    res_body = JSON.parse(res.body)

    temp = res_body['main']['temp']
    celsius = temp - 273.15
    celsius_round = celsius.round

    return "La température actuelle de Nerima#{celsius_round.to_s}C'est ℃."
  end
end

Modifier main.rb

ruby:./main.rb


require 'slack-ruby-client'
require 'sinatra'
require './src/weather'

Slack.configure do |conf|
  conf.token = #Jeton SlackBot
end

get '/' do
  'This is SlackBot on AWS Lambda'
end

post '/webhook' do
  client = Slack::Web::Client.new

  channel_id = params['channel_id']
  command = params['command']

  case command
    when '/nerima'
    #Commande Slash "/Lorsque "nerima" est exécuté, le traitement suivant est exécuté.
      weather = Weather.new
      client.chat_postMessage channel: channel_id, text: weather.current_temp('Nerima'), as_user: true
      # 'Nerima'Vous pouvez changer la partie de. Si vous changez pour "Shinjuku", la température à Shinjuku devrait être retournée.
  end

  return
end

Consultez l'article suivant pour savoir comment obtenir un jeton SlackBot.

Référence: [Création d'un bot à utiliser dans l'espace de travail](https://slack.com/intl/ja-jp/help/articles/115005265703-%E3%83%AF%E3%83%BC%E3%82% AF% E3% 82% B9% E3% 83% 9A% E3% 83% BC% E3% 82% B9% E3% 81% A7% E5% 88% A9% E7% 94% A8% E3% 81% 99% E3% 82% 8B% E3% 83% 9C% E3% 83% 83% E3% 83% 88% E3% 81% AE% E4% BD% 9C% E6% 88% 90) Voir aussi: Génération et régénération de jetons API (https://slack.com/intl/ja-jp/help/articles/215770388-API-%E3%83%88%E3%83%BC%E3%82 % AF% E3% 83% B3% E3% 81% AE% E7% 94% 9F% E6% 88% 90% E3% 81% A8% E5% 86% 8D% E7% 94% 9F% E6% 88% 90 )

Contrôle de fonctionnement réel

Il y a quelques choses que vous devez faire pour appeler SlackBot avec la commande slash.

https://api.slack.com/apps/ スクリーンショット 2020-09-21 21.33.08.png Accédez à l'URL ci-dessus et sélectionnez le Bot concerné.

スクリーンショット 2020-09-21 21.37.35.png Il y a un élément appelé "Commandes Slash" dans le menu de gauche, alors sélectionnez-le et cliquez sur "Créer une nouvelle commande". スクリーンショット 2020-09-21 21.40.08.png Entrez chaque élément.

--Commande: toute commande de barre oblique. ――Cette fois, il est supposé que la température actuelle du Tokyo Degree Nerima Ward sera renvoyée, elle est donc définie sur "/ nerima", mais dans Shinjuku Ward, par exemple, "/ shinjuku" est OK. ) --Request URL: L'URL que vous souhaitez demander lorsque vous exécutez la commande slash.

Cliquez sur "Enregistrer" en bas à droite lorsque la saisie est terminée.

スクリーンショット 2020-09-21 21.53.38.png Après avoir créé la commande slash, essayez de taper "/ nerima" sur le canal où vous avez ajouté le SlackBot. J'espère que vous obtiendrez une réponse de SlackBot comme l'image. (Il est également possible de changer l'image et le nom dans les paramètres.) スクリーンショット 2020-09-21 22.04.20.png Si quelque chose ne va pas, le journal doit être sorti sur le terminal, donc déboguer le cas échéant.

Déployer sur AWS Lambda

Après avoir confirmé l'opération normalement, il est enfin prêt pour la production sur AWS Lambda.

Installez l'AWS CLI

Cette fois, nous procéderons au déploiement à l'aide d'un outil appelé «AWS CLI», donc si vous ne l'avez pas encore installé, installez-le.

$ brew install awscli

Créer un utilisateur IAM

Créez un utilisateur IAM pour effectuer le travail de déploiement. スクリーンショット 2020-09-21 22.11.08.png Tout d'abord, allez dans "IAM" -> "Stratégie" -> "Créer une stratégie" et collez l'instruction suivante à partir de l'onglet JSON. スクリーンショット 2020-09-21 22.13.26.png

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "apigateway:*",
                "cloudformation:*",
                "dynamodb:*",
                "events:*",
                "iam:*",
                "lambda:*",
                "logs:*",
                "route53:*",
                "s3:*"
             ],
            "Resource": [
                "*"
            ]
        }
    ]
}

Voir aussi: Stratégie IAM de déploiement minimal (https://rubyonjets.com/docs/extras/minimal-deploy-iam/)

スクリーンショット 2020-09-21 22.15.47.png Entrez le nom et la description de la politique, le cas échéant, puis cliquez sur «Créer une politique».

スクリーンショット 2020-09-21 22.17.27.png Ensuite, allez dans "IAM" -> "Utilisateur" -> "Créer un utilisateur", donnez-lui un nom approprié, cochez "Accès par programme" et passez au suivant.

スクリーンショット 2020-09-21 22.17.47.png Sélectionnez «Déploiement minimal de la stratégie IAM» créée précédemment à partir de «Joindre directement la stratégie existante» et passez à la suivante.

スクリーンショット 2020-09-21 22.17.59.png

(Les balises sont facultatives) Enfin, un écran de confirmation s'affiche. S'il n'y a pas de problème, cliquez sur "Créer un utilisateur".

スクリーンショット 2020-09-21 22.18.13_censored.jpg Ensuite, deux «ID de clé d'accès» et «clé d'accès secrète» seront émis, alors gardez-le en lieu sûr pendant que vous téléchargez le fichier csv ou que vous en prenez note.

Paramètres de l'AWS CLI

$ aws configure

AWS Access Key ID #ID de clé d'accès créé précédemment
AWS Secret Access Key #La clé d'accès secrète que vous avez créée précédemment
Default region name # ap-northeast-1 
Default output format # json 

Lorsque vous tapez "aws configure" dans le terminal, il vous sera demandé différentes choses de manière interactive, alors entrez les informations nécessaires pour chacune.

Créer divers fichiers

Après avoir configuré l'AWS CLI, créez divers fichiers requis pour le déploiement.

ruby:./config.ru


require 'rack'
require 'rack/contrib'
require_relative './main'

set :root, File.dirname(__FILE__)

run Sinatra::Application

ruby:./lambda.rb


require 'json'
require 'rack'
require 'base64'

$app ||= Rack::Builder.parse_file("#{__dir__}/config.ru").first
ENV['RACK_ENV'] ||= 'production'

def handler(event:, context:)
  body = if event['isBase64Encoded']
    Base64.decode64 event['body']
  else
    event['body']
  end || ''

  headers = event.fetch 'headers', {}

  env = {
    'REQUEST_METHOD' => event.fetch('httpMethod'),
    'SCRIPT_NAME' => '',
    'PATH_INFO' => event.fetch('path', ''),
    'QUERY_STRING' => Rack::Utils.build_query(event['queryStringParameters'] || {}),
    'SERVER_NAME' => headers.fetch('Host', 'localhost'),
    'SERVER_PORT' => headers.fetch('X-Forwarded-Port', 443).to_s,

    'rack.version' => Rack::VERSION,
    'rack.url_scheme' => headers.fetch('CloudFront-Forwarded-Proto') { headers.fetch('X-Forwarded-Proto', 'https') },
    'rack.input' => StringIO.new(body),
    'rack.errors' => $stderr,
  }

  headers.each_pair do |key, value|
    name = key.upcase.gsub '-', '_'
    header = case name
      when 'CONTENT_TYPE', 'CONTENT_LENGTH'
        name
      else
        "HTTP_#{name}"
    end
    env[header] = value.to_s
  end

  begin
    status, headers, body = $app.call env

    body_content = ""
    body.each do |item|
      body_content += item.to_s
    end

    response = {
      'statusCode' => status,
      'headers' => headers,
      'body' => body_content
    }
    if event['requestContext'].has_key?('elb')
      response['isBase64Encoded'] = false
    end
  rescue Exception => exception
    response = {
      'statusCode' => 500,
      'body' => exception.message
    }
  end

  response
end

template.yaml


AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
  SinatraFunction:
    Type: 'AWS::Serverless::Function'
    Properties:
      FunctionName: SlackBot
      Handler: lambda.handler
      Runtime: ruby2.5
      CodeUri: './'
      MemorySize: 512
      Timeout: 30
      Events:
        SinatraApi:
            Type: Api
            Properties:
                Path: /
                Method: ANY
                RestApiId: !Ref SinatraAPI
  SinatraAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: SlackBotAPI
      StageName: Prod
      DefinitionBody:
        swagger: '2.0'
        basePath: '/Prod'
        info:
          title: !Ref AWS::StackName
        paths:
          /{proxy+}:
            x-amazon-apigateway-any-method:
              responses: {}
              x-amazon-apigateway-integration:
                uri:
                  !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SinatraFunction.Arn}/invocations'
                passthroughBehavior: 'when_no_match'
                httpMethod: POST
                type: 'aws_proxy'
          /:
            get:
              responses: {}
              x-amazon-apigateway-integration:
                uri:
                  !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SinatraFunction.Arn}/invocations'
                passthroughBehavior: 'when_no_match'
                httpMethod: POST
                type: 'aws_proxy'
  ConfigLambdaPermission:
    Type: 'AWS::Lambda::Permission'
    DependsOn:
    - SinatraFunction
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref SinatraFunction
      Principal: apigateway.amazonaws.com
Outputs:
  SinatraAppUrl:
    Description: App endpoint URL
    Value: !Sub "https://${SinatraAPI}.execute-api.${AWS::Region}.amazonaws.com/Prod/"

J'omettrai ici ce que chacun représente. (Parce que cette zone utilise le document officiel aws presque tel quel) Voir aussi: aws-samples / serverless-sinatra-sample

Créer un compartiment S3

Puisqu'il est nécessaire de préparer le compartiment AWS S3 à l'avance, créez un compartiment S3 approprié.

Référence: Comment créer un compartiment pour AWS S3

Déployer

Exécutez la commande suivante.

$ aws cloudformation package \
     --template-file template.yaml \
     --output-template-file serverless-output.yaml \
     --s3-bucket #Nom du compartiment S3 créé précédemment

Uploading to a3a55f6abf5f21a2e1161442e53b27a8  12970487 / 12970487.0  (100.00%)
Successfully packaged artifacts and wrote output template to file serverless-output.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /Users/Nom d'utilisateur/Nom du répertoire/serverless-output.yaml --stack-name <YOUR STACK NAME>

Ensuite, un fichier appelé "serverless-output.yaml" devrait être automatiquement généré dans le répertoire, alors exécutez la commande suivante en fonction de cela.

$ aws cloudformation deploy --template-file serverless-output.yaml \
     --stack-name slack-bot \
     --capabilities CAPABILITY_IAM

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - slack-bot

Si «Successfully» s'affiche, le déploiement est réussi.

スクリーンショット 2020-09-21 22.49.32_censored.jpg

Si vous allez dans "Lambda" -> "Fonction", le contenu que vous avez déployé précédemment sera affiché, alors accédez au point de terminaison de l'API décrit dans "Passerelle API".

スクリーンショット 2020-09-21 22.53.09.png

ruby:./main.rb


get '/' do
  'This is SlackBot on AWS Lambda'
end

Si "Ceci est SlackBot sur AWS Lambda" est renvoyé comme prévu dans la requête get '/' dans main.rb, il est normal de juger qu'il fonctionne correctement.

Modifier l'URL de demande pour les commandes Slash

https://api.slack.com/apps/

スクリーンショット 2020-09-21 23.00.35_censored.jpg Revenez à la page des paramètres de SlackBot et changez l'URL de demande de "Commandes Slash" au point de terminaison que vous venez de créer. (Https: //********.execute-api.ap-northeast-1.amazonaws.com/Prod/webhook ")

スクリーンショット 2020-09-21 23.06.41.png Enfin, j'ai de nouveau tapé "/ nerima" sur le canal Slack, et j'étais heureux si la réponse revenait correctement.

スクリーンショット 2020-09-21 23.07.45.png Si cela ne fonctionne pas, le journal doit être envoyé vers CloudWatch, alors déboguez-le en conséquence.

Épilogue

Je vous remercie pour votre travail acharné!

Cette fois, j'ai touché AWS Lambda avec le thème de l'exécution d'un simple SlackBot avec Lambda. Je ne pouvais pas vraiment réaliser toute la grandeur de Lamda car je n'ai pas implémenté beaucoup de fonctions, mais je pense que c'est un service très pratique s'il est bien utilisé.

Je n'ai pas fait d'opérations difficiles, donc fondamentalement, cela devrait fonctionner si vous suivez la procédure, mais s'il y a quelque chose de coincé, j'apprécierais que vous puissiez le signaler dans les commentaires.

Recommended Posts

Essayez d'exécuter SlackBot réalisé avec Ruby x Sinatra sur AWS Lambda
Essayez d'exécuter une application créée avec Quarkus sur Heroku
Créer un programme périodique avec Ruby x AWS Lambda x CloudWatch Events
Présentation de Rspec avec Ruby on Rails x Docker
Publiez l'application avec ruby on rails
J'ai fait un portfolio avec Ruby On Rails
Notifier quotidiennement Slack des factures AWS avec Lambda pour Ruby
Publiez régulièrement des images de tweets sur Twitter avec AWS Lambda + Java
Créer un SlackBot avec AWS lambda et API Gateway en Java
Créez AWS Lambda avec Quarkus
Quand j'ai essayé d'utiliser le kit AWS SDK avec Ruby + Lambda, `sam local` était en panne.
Avec [AWS] CodeStar, vous pouvez créer un projet Spring (Java) s'exécutant sur Lambda en seulement 3 minutes! !!
Installez Ruby sur MSYS2 avec pacman
[Ruby on Rails] Read try (: [] ,: key)
Essayez d'exécuter cloudera manager avec docker
Java sur AWS Lambda est-il lent?
Programmation avec ruby (en route)
Hello World avec AWS Lambda + Java
Essayez d'exécuter Spring Boot sur Kubernetes
Essayez d'exécuter AWS X-Ray en Java
Installez ruby sur Ubuntu 20.04 avec rbenv
Exécuter des binaires C sur AWS Lambda
Comment créer un environnement de développement Ruby on Rails avec Docker (Rails 6.x)
Premiers pas avec Micronaut 2.x ~ Construction native et déploiement sur AWS Lambda ~
Comment créer un environnement de développement Ruby on Rails avec Docker (Rails 5.x)