Getting Started with Rails #

Rails sample app

In this tutorial, you will deploy the sample application from Michael Hartl’s book Ruby on Rails Tutorial: Learn Web Development with Rails. It’s a simple micro-blogging application that lets you create posts and follow other users. It leverages a PostgreSQL database and stores file uploads in an S3 Object Store. We will explain all the necessary SetOps commands that we need to deploy the application. You can find a summary of all commands at the end.

Prepare your Code #

  1. Get started by getting the code. The code is originally hosted at mhartl/sample_app_6th_ed, but for convenience, we recommend using our fork at setopsco/rails-sample-app

    This will provide you with a verified version, and all necessary adjustments towards a Twelve-Factor App have already been made.

    git clone https://github.com/setopsco/rails-sample-app
    

Prepare your SetOps Environment #

At first, you need to choose a name for project, stage, and app. You can edit them in the form in the top right corner.

  1. Now we’re ready to deploy this app to SetOps. Start by creating a Project.

    setops -p <PROJECT> project:create
    
  2. Create a Stage for your project.

    setops -p <PROJECT> -s <STAGE> stage:create
    
    project and stage must only contain lowercase letters a-z and numbers 0-9 and start with a lowercase letter. The length of project has to be between 3 and 20 characters and the length of stage between 3 and 12. It also has to start with a lowercase letter. A valid example is parkscheibe & staging.
  3. Create the Stage Definition containing the App and store it as <STAGE>.setops.yaml.

    schema_version: "1"
    project: <PROJECT>
    stage: <STAGE>
    apps:
      # The name for apps must only contain lowercase letters `a-z` and numbers `0-9` and dashes `-`. The name must be between 3 and 16 characters long and start with a lowercase letter.
      <APPNAME>:
        container:
          # To get the Rails app started inside the container, we need to set a command
          command:
            - bundle
            - exec
            - puma
          # Let's also configure a container health check, which is executed in the container and checks if our app is healthy.
          health_check:
            command:
              - /bin/sh
              - -c
              - curl -s http://localhost:$PORT/.well-known/health-check | grep ok
            interval: 15
            retries: 10
            start_period: 30
            timeout: 5
        env:
          # We map a secret (which we will set in the next step) to an env variable
          SECRET_KEY_BASE:
            description: "Key Base which is required for Rails Sessions"
            value: "{{ .Secrets.secret_key_base }}"
        links:
          database:
            env_key: DATABASE_URL
          store:
            env_key: S3_DATA_URL
        network:
          # We want it to be publicly reachable, so we set the network's public option to true.
          public: true
          # The app will accept http requests
          protocol: http
          # Rails will listen on port 5000, so we need to tell SetOps that
          ports:
            - 5000
          health_check:
            status: "200"
            path: "/.well-known/health-check"
        resources:
          # we want only one instance running
          scale: 1
          # the smallest cpu sizing is enough for this app
          cpu: 128
          # we need to change the available memory for a container since Rails' memory consumption is higher then the default
          memory: 512
    services:
      # The name for services must only contain lowercase letters `a-z` and numbers `0-9` and dashes `-`. The name must be between 3 and 18 characters long and start with a lowercase letter.
      database:
        type: postgresql
        plan: shared
        version: "11"
      store:
        type: s3
    
  4. Create the Secret which we map in the Stage Definition.

    setops -p <PROJECT> -s <STAGE> secret:create secret_key_base=$(openssl rand -hex 64)
    
  5. Apply the Stage Definition. You will see a diff to the current state and you will be asked to confirm that you want to apply these changes.

    setops -p <PROJECT> -s <STAGE> stage:apply -f stage.setops.yaml
    

Deploy your Image #

  1. Build and push the image from the repo cloned earlier to the SetOps Image Registry. Also initialize the database schema and load some sample data from the seeds (db/seeds.rb).

    cd /path/to/cloned/repository # from step 1
    setops -p <PROJECT> -s <STAGE> --app <APPNAME> image:push --tag v1.0.0 --build-with-docker .
    
    image:push with the --build-with-docker flag builds and pushes a new image to SetOps. You can find more information about the distinct steps and how to run them isolated here.

    If you encounter any errors during the image build, try to run the command without caching:

    cd /path/to/cloned/repository # from step 1
    setops -p <PROJECT> -s <STAGE> --app <APPNAME> image:push --tag v1.0.0 --build-with-docker . --no-cache
    
  2. Run migrations and seed database before deploying the new image

    setops -p <PROJECT> -s <STAGE> --app <APPNAME> task:run --image-tag v1.0.0 -- env DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:schema:load db:seed
    
  3. Deploy the new image to your apps.

    setops -p <PROJECT> -s <STAGE> stage:apply --image-tags <APPNAME>=v1.0.0
    
  4. Verify your app is running with the correct image (v1.0.0) and its health status is HEALTHY.

    setops -p <PROJECT> -s <STAGE> --app <APPNAME> task
    
  5. Get the public domain to your app and copy the domain (<APPNAME>.<STAGE>.<PROJECT>.$YOURDOMAIN)

    setops -p <PROJECT> -s <STAGE> --app <APPNAME> domain
    
  6. Open the application in your browser. You can log in with the sample user defined in db/seeds.rb: the username is example@railstutorial.org with password foobar. Enjoy!

If you want to remove the stage & project again, run these commands:

setops -p <PROJECT> -s <STAGE> stage:destroy --force
setops -p <PROJECT> project:destroy --force