Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Operationalizing Serverless: New Developer

Operationalizing Serverless: New Developer

Slides for the ServerlessOps Operationalizing Serverless: New Developer workshop.

Tom McLaughlin

April 03, 2018
Tweet

More Decks by Tom McLaughlin

Other Decks in Technology

Transcript

  1. TEXT OBJECTIVES ▸ Learn what serverless on AWS looks like

    ▸ Go through an example developer workflow ▸ Debug a system failure
  2. TEXT HOW WE’LL ACCOMPLISH THIS ▸ Deploy an example website

    and service ▸ Develop and deploy a new feature ▸ Debug an alert that has triggered
  3. WHAT IS SERVERLESS? ▸ No servers to manage or provision

    ▸ Consumption (not capacity) priced ▸ Never pay for idle ▸ Feature of the event based nature of the architecture ▸ Components scales with usage ▸ You are responsible for maintaining performance and reliability ▸ Availability and fault tolerance built in ▸ Everything is a system
  4. TEXT OUR AWS ENVIRONMENT ▸ 3 AWS Accounts ▸ Prime

    (user management), Prod, and Dev ▸ Dev includes personal developer environments. ▸ Developer rights. ▸ Dev: wide rights ▸ Prod: limited rights
  5. TEXT SERVERLESS FRAMEWORK ▸ DSL for describing serverless systems ▸

    Supports multiple cloud providers ▸ We we chose it because ▸ Provides deploy, testing, and debugging capabilities ▸ Plugins make it extensible
  6. TEXT WILD RYDES SERVICES: WEBSITE - WILD-RIDES-WEBSITE ▸ S3 performs

    web hosting ▸ No nginx, apache, etc. ▸ Cost is based on use ▸ Hosts all site static assets ▸ HTML ▸ JavaScript ▸ CSS ▸ Images
  7. TEXT WILD RYDES SERVICES: AUTH - WILD-RYDES-AUTH ▸ Cognito handles

    user: ▸ Management ▸ Authentication / Authorization
  8. TEXT WILD RYDES SERVICES: REQUEST RIDE - WILD-RYDES-RIDE-REQUESTS ▸ API

    Gateway + Lambda + DynamoDB ▸ Backend to request and record rides ▸ No webserver involved ▸ APIG has an endoint and knows to invoke our Lambda when that is called. ▸ DynamoDB stores all ride request info
  9. TEXT DEPLOY AND SIGNUP FOR WILD RYDES ▸ Deploy services

    ▸ Signup, confirm, login, & hail ride ▸ Questions ▸ How is the website updated with Cognito setup information? ▸ Give alternative ways to accomplish this. ▸ How might you refactor the Unicorn stable?
  10. TEXT WHAT IS PROMO DISCOUNT SERVICE ▸ Given a username

    and location ▸ Randomly returns a random discount value. ▸ We’re adding some gamification to test ▸ Retention ▸ Revenue
  11. TEXT DEPLOY PROMO DISCOUNT SERVICE AND REQUEST RIDE DISCOUNT FEATURE

    ▸ Promo Discount ▸ REST API for returning a discount ▸ Ride Request ▸ Calls Promo Discount and records the discount value with rest of ride info
  12. TEXT LOCAL TESTING ▸ Run local unit tests. ▸ We

    use Moto to mock AWS services ▸ Let’s us test against (fake) AWS resources without deploying @mock_sts # Let's us handle assumed roles. @mock_dynamodb2 def test__record_ride(ride, ride_id): '''Test recording a ride''' ddb = boto3.client('dynamodb') ddb.create_table( TableName=DYNAMODB_TABLE, KeySchema=[ { 'AttributeName': DYNAMODB_HASH_KEY, 'KeyType': 'HASH' } ], AttributeDefinitions=[{'AttributeName': DYNAMODB_HASH_KEY, 'AttributeType': 'S'}], ProvisionedThroughput={'ReadCapacityUnits': 1, 'WriteCapacityUnits': 1} ) h._record_ride(ride) this_item = ddb.get_item(TableName=DYNAMODB_TABLE, Key={DYNAMODB_HASH_KEY: {'S': ride_id}}) assert this_item.get('Item').get(DYNAMODB_HASH_KEY).get('S') == ride_id
  13. TEXT DEPLOY AND TEST PROMO DISCOUNT ▸ Test locally ▸

    Test remotely ▸ Questions: ▸ Where is the security risk we've potentially just introduced? ▸ How did we have service discovery between Ride Requests and Promo Discount?
  14. TEXT TRAVIS CI/CD PIPELINE ▸ What is Travis ▸ Why

    I chose it ▸ How it’s setup ▸ Consistent setup across projects ▸ Modular configuration ▸ Single artifact from testing to deploy
  15. TEXT CI/CD QUESTIONS ▸ Questions ▸ How might we speed

    up the build? ▸ How might we simplify tighten deploy user setup?
  16. TEXT IOPIPE: FUNCTION INSTRUMENTATION ▸ Instrument function ▸ Deploy ▸

    Run artillery ▸ View alert ▸ See Tracing in IOpipe diff --git a/handlers/request_ride.py b/handlers/request_ride.py index b04f33e..996bc54 100644 --- a/handlers/request_ride.py +++ b/handlers/request_ride.py @@ -122,6 +122,9 @@ def _record_ride(ride_item): @iopipe def handler(event, context): '''Function entry''' + + context.iopipe.mark.start('request_ride') + _logger.debug('Request: {}'.format(json.dumps(event))) # IOpipe state. @@ -140,17 +143,27 @@ def handler(event, context): } else: - user = _get_user_from_authorizer(authorizer) + with context.iopipe.mark('get_user_from_authorizer'): + user = _get_user_from_authorizer(authorizer) + body = json.loads(event.get('body')) - pickup_location = _get_pickup_location(body) - ride_resp = _get_ride(user, pickup_location) + + with context.iopipe.mark('get_pickup_location'): + pickup_location = _get_pickup_location(body) + + with context.iopipe.mark('get_ride'): + ride_resp = _get_ride(user, pickup_location) + + with context.iopipe.mark('get_ride_discount'): + discount_multiplier = _get_ride_discount(user, pickup_location) + + with context.iopipe.mark('record_ride'): + _record_ride(ride_resp) # Note: testing discount feature: discount_multiplier = _get_ride_discount(user, pickup_location) ride_resp['DiscountMultiplier'] = discount_multiplier - _record_ride(ride_resp) - resp = { 'statusCode': 201, 'body': json.dumps(ride_resp), @@ -158,5 +171,6 @@ def handler(event, context): "Access-Control-Allow-Origin": "*", } } + context.iopipe.mark.end('request_ride') return resp