One place for hosting & domains

      Pipeline

      How To Set Up a CD Pipeline with Spinnaker on DigitalOcean Kubernetes


      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Spinnaker is an open-source resource management and continuous delivery application for fast, safe, and repeatable deployments, using a powerful and customizable pipeline system. Spinnaker allows for automated application deployments to many platforms, including DigitalOcean Kubernetes. When deploying, you can configure Spinnaker to use built-in deployment strategies, such as Highlander and Red/black, with the option of creating your own deployment strategy. It can integrate with other DevOps tools, like Jenkins and TravisCI, and can be configured to monitor GitHub repositories and Docker registries.

      Spinnaker is managed by Halyard, a tool specifically built for configuring and deploying Spinnaker to various platforms. Spinnaker requires external storage for persisting your application’s settings and pipelines. It supports different platforms for this task, like DigitalOcean Spaces.

      In this tutorial, you’ll deploy Spinnaker to DigitalOcean Kubernetes using Halyard, with DigitalOcean Spaces as the underlying back-end storage. You’ll also configure Spinnaker to be available at your desired domain, secured using Let’s Encrypt TLS certificates. Then, you will create a sample application in Spinnaker, create a pipeline, and deploy a Hello World app to your Kubernetes cluster. After testing it, you’ll introduce authentication and authorization via GitHub Organizations. By the end, you will have a secured and working Spinnaker deployment in your Kubernetes cluster.

      Note: This tutorial has been specifically tested with Spinnaker 1.13.5.

      Prerequisites

      • Halyard installed on your local machine, according to the official instructions. Please note that using Halyard on Ubuntu versions higher than 16.04 is not supported. In such cases, you can use it via Docker.

      • A DigitalOcean Kubernetes cluster with your connection configured as the kubectl default. The cluster must have at least 8GB RAM and 4 CPU cores available for Spinnaker (more will be required in the case of heavier use). Instructions on how to configure kubectl are shown under the Connect to your Cluster step shown when you create your cluster. To create a Kubernetes cluster on DigitalOcean, see the Kubernetes Quickstart.

      • An Nginx Ingress Controller and cert-manager installed on the cluster. For a guide on how to do this, see How to Set Up an Nginx Ingress with Cert-Manager on DigitalOcean Kubernetes.

      • A DigitalOcean Space with API keys (access and secret). To create a DigitalOcean Space and API keys, see How To Create a DigitalOcean Space and API Key.

      • A domain name with three DNS A records pointed to the DigitalOcean Load Balancer used by the Ingress. If you’re using DigitalOcean to manage your domain’s DNS records, consult How to Create DNS Records to create A records. In this tutorial, we’ll refer to the A records as spinnaker.example.com, spinnaker-api.example.com, and hello-world.example.com.

      • A GitHub account, added to a GitHub Organization with admin permissions and public visibility. The account must also be a member of a Team in the Organization. This is required to complete Step 5.

      Step 1 — Adding a Kubernetes Account with Halyard

      In this section, you will add a Kubernetes account to Spinnaker via Halyard. An account, in Spinnaker’s terms, is a named credential it uses to access a cloud provider.

      As part of the prerequisite, you created the echo1 and echo2 services and an echo_ingress ingress for testing purposes; you will not need these in this tutorial, so you can now delete them.

      Start off by deleting the ingress by running the following command:

      • kubectl delete -f echo_ingress.yaml

      Then, delete the two test services:

      • kubectl delete -f echo1.yaml && kubectl delete -f echo2.yaml

      The kubectl delete command accepts the file to delete when passed the -f parameter.

      Next, from your local machine, create a folder that will serve as your workspace:

      Navigate to your workspace by running the following command:

      Halyard does not yet know where it should deploy Spinnaker. Enable the Kubernetes provider with this command:

      • hal config provider kubernetes enable

      You'll receive the following output:

      Output

      + Get current deployment Success + Edit the kubernetes provider Success Problems in default.provider.kubernetes: - WARNING Provider kubernetes is enabled, but no accounts have been configured. + Successfully enabled kubernetes

      Halyard logged all the steps it took to enable the Kubernetes provider, and warned that no accounts are defined yet.

      Next, you'll create a Kubernetes service account for Spinnaker, along with RBAC. A service account is a type of account that is scoped to a single namespace. It is used by software, which may perform various tasks in the cluster. RBAC (Role Based Access Control) is a method of regulating access to resources in a Kubernetes cluster. It limits the scope of action of the account to ensure that no important configurations are inadvertently changed on your cluster.

      Here, you will grant Spinnaker cluster-admin permissions to allow it to control the whole cluster. If you wish to create a more restrictive environment, consult the official Kubernetes documentation on RBAC.

      First, create the spinnaker namespace by running the following command:

      • kubectl create ns spinnaker

      The output will look like:

      Output

      namespace/spinnaker created

      Run the following command to create a service account named spinnaker-service-account:

      • kubectl create serviceaccount spinnaker-service-account -n spinnaker

      You've used the -n flag to specify that kubectl create the service account in the spinnaker namespace. The output will be:

      Output

      serviceaccount/spinnaker-service-account created

      Then, bind it to the cluster-admin role:

      • kubectl create clusterrolebinding spinnaker-service-account --clusterrole cluster-admin --serviceaccount=spinnaker:spinnaker-service-account

      You will see the following output:

      Output

      clusterrolebinding.rbac.authorization.k8s.io/spinnaker-service-account created

      Halyard uses the local kubectl to access the cluster. You'll need to configure it to use the newly created service account before deploying Spinnaker. Kubernetes accounts authenticate using usernames and tokens. When a service account is created, Kubernetes makes a new secret and populates it with the account token. To retrieve the token for the spinnaker-service-account, you'll first need to get the name of the secret. You can fetch it into a console variable, named TOKEN_SECRET, by running:

      • TOKEN_SECRET=$(kubectl get serviceaccount -n spinnaker spinnaker-service-account -o jsonpath='{.secrets[0].name}')

      This gets information about the spinnaker-service-account from the namespace spinnaker, and fetches the name of the first secret it contains by passing in a JSON path.

      Fetch the contents of the secret into a variable named TOKEN by running:

      • TOKEN=$(kubectl get secret -n spinnaker $TOKEN_SECRET -o jsonpath='{.data.token}' | base64 --decode)

      You now have the token available in the environment variable TOKEN. Next, you'll need to set credentials for the service account in kubectl:

      • kubectl config set-credentials spinnaker-token-user --token $TOKEN

      You will see the following output:

      Output

      User "spinnaker-token-user" set.

      Then, you'll need to set the user of the current context to the newly created spinnaker-token-user by running the following command:

      • kubectl config set-context --current --user spinnaker-token-user

      By setting the current user to spinnaker-token-user, kubectl is now configured to use the spinnaker-service-account, but Halyard does not know anything about that. Add an account to its Kubernetes provider by executing:

      • hal config provider kubernetes account add spinnaker-account --provider-version v2

      The output will look like this:

      Output

      + Get current deployment Success + Add the spinnaker-account account Success + Successfully added account spinnaker-account for provider kubernetes.

      This commmand adds a Kubernetes account to Halyard, named spinnaker-account, and marks it as a service account.

      Generally, Spinnaker can be deployed in two ways: distributed installation or local installation. Distributed installation is what you're completing in this tutorial—you're deploying it to the cloud. Local installation, on the other hand, means that Spinnaker will be downloaded and installed on the machine Halyard runs on. Because you're deploying Spinnaker to Kubernetes, you'll need to mark the deployment as distributed, like so:

      • hal config deploy edit --type distributed --account-name spinnaker-account

      Since your Spinnaker deployment will be building images, it is necessary to enable artifacts in Spinnaker. You can enable them by running the following command:

      • hal config features edit --artifacts true

      Here you've enabled artifacts to allow Spinnaker to store more metadata about the objects it creates.

      You've added a Kubernetes account to Spinnaker, via Halyard. You enabled the Kubernetes provider, configured RBAC roles, and added the current kubectl config to Spinnaker, thus adding an account to the provider. Now you'll set up your back-end storage.

      Step 2 — Configuring the Space as the Underlying Storage

      In this section, you will configure the Space as the underlying storage for the Spinnaker deployment. Spinnaker will use the Space to store its configuration and pipeline-related data.

      To configure S3 storage in Halyard, run the following command:

      • hal config storage s3 edit --access-key-id your_space_access_key --secret-access-key --endpoint spaces_endpoint_with_region_prefix --bucket space_name --no-validate

      Remember to replace your_space_access_key with your Space access key and spaces_endpoint_with_region_prefix with the endpoint of your Space. This is usually region-id.digitaloceanspaces.com, where region-id is the region of your Space. You can replace space_name with the name of your Space. The --no-validate flag tells Halyard not to validate the settings given right away, because DigitalOcean Spaces validation is not supported.

      Once you've run this command, Halyard will ask you for your secret access key. Enter it to continue and you'll then see the following output:

      Output

      + Get current deployment Success + Get persistent store Success + Edit persistent store Success + Successfully edited persistent store "s3".

      Now that you've configured s3 storage, you'll ensure that your deployment will use this as its storage by running the following command:

      • hal config storage edit --type s3

      The output will look like this:

      Output

      + Get current deployment Success + Get persistent storage settings Success + Edit persistent storage settings Success + Successfully edited persistent storage.

      You've set up your Space as the underlying storage that your instance of Spinnaker will use. Now you'll deploy Spinnaker to your Kubernetes cluster and expose it at your domains using the Nginx Ingress Controller.

      Step 3 — Deploying Spinnaker to Your Cluster

      In this section, you will deploy Spinnaker to your cluster using Halyard, and then expose its UI and API components at your domains using an Nginx Ingress. First, you'll configure your domain URLs: one for Spinnaker's user interface and one for the API component. Then you'll pick your desired version of Spinnaker and deploy it using Halyard. Finally you'll create an ingress and configure it as an Nginx controller.

      First, you'll need to edit Spinnaker's UI and API URL config values in Halyard and set them to your desired domains. To set the API endpoint to your desired domain, run the following command:

      • hal config security api edit --override-base-url https://spinnaker-api.example.com

      The output will look like:

      Output

      + Get current deployment Success + Get API security settings Success + Edit API security settings Success ...

      To set the UI endpoint to your domain, which is where you will access Spinnaker, run:

      • hal config security ui edit --override-base-url https://spinnaker.example.com

      The output will look like:

      Output

      + Get current deployment Success + Get UI security settings Success + Edit UI security settings Success + Successfully updated UI security settings.

      Remember to replace spinnaker-api.example.com and spinnaker.example.com with your domains. These are the domains you have pointed to the Load Balancer that you created during the Nginx Ingress Controller prerequisite.

      You've created and secured Spinnaker's Kubernetes account, configured your Space as its underlying storage, and set its UI and API endpoints to your domains. Now you can list the available Spinnaker versions:

      Your output will show a list of available versions. At the time of writing this article 1.13.5 was the latest version:

      Output

      + Get current deployment Success + Get Spinnaker version Success + Get released versions Success + You are on version "", and the following are available: - 1.11.12 (Cobra Kai): Changelog: https://gist.GitHub.com/spinnaker-release/29a01fa17afe7c603e510e202a914161 Published: Fri Apr 05 14:55:40 UTC 2019 (Requires Halyard >= 1.11) - 1.12.9 (Unbreakable): Changelog: https://gist.GitHub.com/spinnaker-release/7fa9145349d6beb2f22163977a94629e Published: Fri Apr 05 14:11:44 UTC 2019 (Requires Halyard >= 1.11) - 1.13.5 (BirdBox): Changelog: https://gist.GitHub.com/spinnaker-release/23af06bc73aa942c90f89b8e8c8bed3e Published: Mon Apr 22 14:32:29 UTC 2019 (Requires Halyard >= 1.17)

      To select a version to install, run the following command:

      • hal config version edit --version 1.13.5

      It is recommended to always select the latest version, unless you encounter some kind of regression.

      You will see the following output:

      Output

      + Get current deployment Success + Edit Spinnaker version Success + Spinnaker has been configured to update/install version "version". Deploy this version of Spinnaker with `hal deploy apply`.

      You have now fully configured Spinnaker's deployment. You'll deploy it with the following command:

      This command could take a few minutes to finish.

      The final output will look like this:

      Output

      + Get current deployment Success + Prep deployment Success + Preparation complete... deploying Spinnaker + Get current deployment Success + Apply deployment Success + Deploy spin-redis Success + Deploy spin-clouddriver Success + Deploy spin-front50 Success + Deploy spin-orca Success + Deploy spin-deck Success + Deploy spin-echo Success + Deploy spin-gate Success + Deploy spin-rosco Success ...

      Halyard is showing you the deployment status of each of Spinnaker's microservices. Behind the scenes, it calls kubectl to install them.

      Kubernetes will take some time—ten minutes on average—to bring all of the containers up, especially for the first time. You can watch the progress by running the following command:

      • kubectl get pods -n spinnaker -w

      You've deployed Spinnaker to your Kubernetes cluster, but it can't be accessed beyond your cluster.

      You'll be storing the ingress configuration in a file named spinnaker-ingress.yaml. Create it using your text editor:

      • nano spinnaker-ingress.yaml

      Add the following lines:

      spinnaker-ingress.yaml

      apiVersion: extensions/v1beta1
      kind: Ingress
      metadata:
        name: spinnaker-ingress
        namespace: spinnaker
        annotations:
          kubernetes.io/ingress.class: nginx
          certmanager.k8s.io/cluster-issuer: letsencrypt-prod
      spec:
        tls:
        - hosts:
          - spinnaker-api.example.com
          - spinnaker.example.com
          secretName: spinnaker
        rules:
        - host: spinnaker-api.example.com
          http:
            paths:
            - backend:
                serviceName: spin-gate
                servicePort: 8084
        - host: spinnaker.example.com
          http:
            paths:
            - backend:
                serviceName: spin-deck
                servicePort: 9000
      

      Remember to replace spinnaker-api.example.com with your API domain, and spinnaker.example.com with your UI domain.

      The configuration file defines an ingress called spinnaker-ingress. The annotations specify that the controller for this ingress will be the Nginx controller, and that the letsencrypt-prod cluster issuer will generate the TLS certificates, defined in the prerequisite tutorial.

      Then, it specifies that TLS will secure the UI and API domains. It sets up routing by directing the API domain to the spin-gate service (Spinnaker's API containers), and the UI domain to the spin-deck service (Spinnaker's UI containers) at the appropriate ports 8084 and 9000.

      Save and close the file.

      Create the Ingress in Kubernetes by running:

      • kubectl create -f spinnaker-ingress.yaml

      You'll see the following output:

      Output

      ingress.extensions/spinnaker-ingress created

      Wait a few minutes for Let's Encrypt to provision the TLS certificates, and then navigate to your UI domain, spinnaker.example.com, in a browser. You will see Spinnaker's user interface.

      Spinnaker's home page

      You've deployed Spinnaker to your cluster, exposed the UI and API components at your domains, and tested if it works. Now you'll create an application in Spinnaker and run a pipeline to deploy the Hello World app.

      Step 4 — Creating an Application and Running a Pipeline

      In this section, you will use your access to Spinnaker at your domain to create an application with it. You'll then create and run a pipeline to deploy a Hello World app, which can be found at paulbouwer/hello-kubernetes. You'll access the app afterward.

      Navigate to your domain where you have exposed Spinnaker's UI. In the upper right corner, press on Actions, then select Create Application. You will see the New Application form.

      Creating a new Application in Spinnaker

      Type in hello-world as the name, input your email address, and press Create.

      When the page loads, navigate to Pipelines by clicking the first tab in the top menu. You will see that there are no pipelines defined yet.

      No pipelines defined in Spinnaker

      Press on Configure a new pipeline and a new form will open.

      Creating a new Pipeline in Spinnaker

      Fill in Deploy Hello World Application as your pipeline's name, and press Create.

      On the next page, click the Add Stage button. As the Type, select Deploy (Manifest), which is used for deploying Kubernetes manifests you specify. For the Stage Name, type in Deploy Hello World. Scroll down, and in the textbox under Manifest Configuration, enter the following lines:

      Manifest Configuration

      apiVersion: extensions/v1beta1
      kind: Ingress
      metadata:
        name: hello-world-ingress
        namespace: spinnaker
        annotations:
          kubernetes.io/ingress.class: nginx
          certmanager.k8s.io/cluster-issuer: letsencrypt-prod
      spec:
        tls:
        - hosts:
          - hello-world.example.com
          secretName: hello-world
        rules:
        - host: hello-world.example.com
          http:
            paths:
            - backend:
                serviceName: hello-kubernetes
                servicePort: 80
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: hello-kubernetes
        namespace: spinnaker
      spec:
        type: ClusterIP
        ports:
        - port: 80
          targetPort: 8080
        selector:
          app: hello-kubernetes
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: hello-kubernetes
        namespace: spinnaker
      spec:
        replicas: 3
        selector:
          matchLabels:
            app: hello-kubernetes
        template:
          metadata:
            labels:
              app: hello-kubernetes
          spec:
            containers:
            - name: hello-kubernetes
              image: paulbouwer/hello-kubernetes:1.5
              ports:
              - containerPort: 8080
      

      Remember to replace hello-world.example.com with your domain, which is also pointed at your Load Balancer.

      In this configuration, you define a Deployment, consisting of three replicas of the paulbouwer/hello-kubernetes:1.5 image. You also define a Service to be able to access it and an Ingress to expose the Service at your domain.

      Press Save Changes in the bottom right corner of the screen. When it finishes, navigate back to Pipelines. On the right side, select the pipeline you just created and press the Start Manual Execution link. When asked to confirm, press Run.

      This pipeline will take a short time to complete. You will see the progress bar complete when it has successfully finished.

      Successfully ran a Pipeline

      You can now navigate to the domain you defined in the configuration. You will see the Hello World app, which Spinnaker just deployed.

      Hello World App

      You've created an application in Spinnaker, ran a pipeline to deploy a Hello World app, and accessed it. In the next step, you will secure Spinnaker by enabling GitHub Organizations authorization.

      Step 5 — Enabling Role-Based Access with GitHub Organizations

      In this section, you will enable GitHub OAuth authentication and GitHub Organizations authorization. Enabling GitHub OAuth authentication forces Spinnaker users to log in via GitHub, therefore preventing anonymous access. Authorization via GitHub Organizations restricts access only to those in an Organization. A GitHub Organization can contain Teams (named groups of members), which you will be able to use to restrict access to resources in Spinnaker even further.

      For OAuth authentication to work, you'll first need to set up the authorization callback URL, which is where the user will be redirected after authorization. This is your API domain ending with /login. You need to specify this manually to prevent Spinnaker and other services from guessing. To configure this, run the following command:

      • hal config security authn oauth2 edit --pre-established-redirect-uri https://spinnaker-api.example.com/login

      You will see this output:

      Output

      + Get current deployment Success + Get authentication settings Success + Edit oauth2 authentication settings Success + Successfully edited oauth2 method.

      To set up OAuth authentication with GitHub, you'll need to create an OAuth application for your Organization. To do so, navigate to your Organization on GitHub, go to Settings, click on Developer Settings, and then select OAuth Apps from the left-hand menu. Afterward, click the New OAuth App button on the right. You will see the Register a new OAuth application form.

      Creating a new OAuth App on GitHub

      Enter spinnaker-auth as the name. For the Homepage URL, enter https://spinnaker.example.com, and for the Authorization callback URL, enter https://spinnaker-api.example.com/login. Then, press Register Application.

      You'll be redirected to the settings page for your new OAuth app. Note the Client ID and Client Secret values—you'll need them for the next command.

      With the OAuth app created, you can configure Spinnaker to use the OAuth app by running the following command:

      • hal config security authn oauth2 edit --client-id client_id --client-secret client_secret --provider GitHub

      Remember to replace client_id and client_secret with the values shown on the GitHub settings page.

      You output will be similar to the following:

      Output

      + Get current deployment Success + Get authentication settings Success + Edit oauth2 authentication settings Success Problems in default.security.authn: - WARNING An authentication method is fully or partially configured, but not enabled. It must be enabled to take effect. + Successfully edited oauth2 method.

      You've configured Spinnaker to use the OAuth app. Now, to enable it, execute:

      • hal config security authn oauth2 enable

      The output will look like:

      Output

      + Get current deployment Success + Edit oauth2 authentication settings Success + Successfully enabled oauth2

      You've configured and enabled GitHub OAuth authentication. Now users will be forced to log in via GitHub in order to access Spinnaker. However, right now, everyone who has a GitHub account can log in, which is not what you want. To overcome this, you'll configure Spinnaker to restrict access to members of your desired Organization.

      You'll need to set this up semi-manually via local config files, because Halyard does not yet have a command for setting this. During deployment, Halyard will use the local config files to override the generated configuration.

      Halyard looks for custom configuration under ~/.hal/default/profiles/. Files named service-name-*.yml are picked up by Halyard and used to override the settings of a particular service. The service that you'll override is called gate, and serves as the API gateway for the whole of Spinnaker.

      Create a file under ~/.hal/default/profiles/ named gate-local.yml:

      • nano ~/.hal/default/profiles/gate-local.yml

      Add the following lines:

      gate-local.yml

      security:
       oauth2:
         providerRequirements:
           type: GitHub
           organization: your_organization_name
      

      Replace your_organization_name with the name of your GitHub Organization. Save and close the file.

      With this bit of configuration, only members of your GitHub Organization will be able to access Spinnaker.

      Note: Only those members of your GitHub Organization whose membership is set to Public will be able to log in to Spinnaker. This setting can be changed on the member list page of your Organization.

      Now, you'll integrate Spinnaker with an even more particular access-rule solution: GitHub Teams. This will enable you to specify which Team(s) will have access to resources created in Spinnaker, such as applications.

      To achieve this, you'll need to have a GitHub Personal Access Token for an admin account in your Organization. To create one, visit Personal Access Tokens and press the Generate New Token button. On the next page, give it a description of your choice and be sure to check the read:org scope, located under admin:org. When you are done, press Generate token and note it down when it appears—you won't be able to see it again.

      To configure GitHub Teams role authorization in Spinnaker, run the following command:

      • hal config security authz github edit --accessToken access_token --organization organization_name --baseUrl https://api.github.com

      Be sure to replace access_token with your personal access token you generated and replace organization_name with the name of the Organization.

      The output will be:

      Output

      + Get current deployment Success + Get GitHub group membership settings Success + Edit GitHub group membership settings Success + Successfully edited GitHub method.

      You've updated your GitHub group settings. Now, you'll set the authorization provider to GitHub by running the following command:

      • hal config security authz edit --type github

      The output will look like:

      Output

      + Get current deployment Success + Get group membership settings Success + Edit group membership settings Success + Successfully updated roles.

      After updating these settings, enable them by running:

      • hal config security authz enable

      You'll see the following output:

      Output

      + Get current deployment Success + Edit authorization settings Success + Successfully enabled authorization

      With all the changes in place, you can now apply the changes to your running Spinnaker deployment. Execute the following command to do this:

      Once it has finished, wait for Kubernetes to propagate the changes. This can take quite some time—you can watch the progress by running:

      • kubectl get pods -n spinnaker -w

      When all the pods' states become Running and availability 1/1, navigate to your Spinnaker UI domain. You will be redirected to GitHub and asked to log in, if you're not already. If the account you logged in with is a member of the Organization, you will be redirected back to Spinnaker and logged in. Otherwise, you will be denied access with a message that looks like this:

      {"error":"Unauthorized", "message":"Authentication Failed: User's provider info does not have all required fields.", "status":401, "timestamp":...}
      

      The effect of GitHub Teams integration is that Spinnaker now translates them into roles. You can use these roles in Spinnaker to incorporate additional restrictions to access for members of particular teams. If you try to add another application, you'll notice that you can now also specify permissions, which combine the level of access—read only or read and write—with a role, for that application.

      You've set up GitHub authentication and authorization. You have also configured Spinnaker to restrict access to members of your Organization, learned about roles and permissions, and considered the place of GitHub Teams when integrated with Spinnaker.

      Conclusion

      You have successfully configured and deployed Spinnaker to your DigitalOcean Kubernetes cluster. You can now manage and use your cloud resources more easily, from a central place. You can use triggers to automatically start a pipeline; for example, when a new Docker image has been added to the registry. To learn more about Spinnaker's terms and architecture, visit the official documentation. If you wish to deploy a private Docker registry to your cluster to hold your images, visit How To Set Up a Private Docker Registry on Top of DigitalOcean Spaces and Use It with DO Kubernetes.



      Source link

      Create a CI/CD Pipeline with Gatsby.js, Netlify and Travis CI


      Updated by Linode

      Contributed by

      Linode


      Use promo code DOCS10 for $10 credit on a new account.

      What is Gatsby?

      Gatsby is a Static Site Generator for React built on Node.js. Gatsby uses a modern web technology stack based on client-side Javascript, reusable APIs, and prebuilt Markdown, otherwise known as the JAMstack. This method of building a site is fast, secure, and scalable. All production site pages are prebuilt and static, so Gatsby does not have to build HTML for each page request.

      What is the CI/CD Pipeline?

      The CI/CD (continuous integration/continuous delivery) pipeline created in this guide is an automated sequence of events that is initiated after you update the code for your website on your local computer. These events take care of the work that you would otherwise need to perform manually: previewing your in-development site, testing your new code, and deploying it to your production server. These actions are powered by GitHub, Netlify, and Travis CI.

      Note

      This guide uses GitHub as your central Git repository, but you can use any service that is compatible with Netlify and Travis.

      Netlify

      Netlify is a PaaS (Platform as a Service) provider that allows you to quickly deploy static sites on the Netlify platform. In this guide Netlify will be used to provide a preview of your Gatsby site while it is in development. This preview can be shared with different stakeholders for site change approvals, or with anyone that is interested in your project. The production version of your website will ultimately be deployed to a Linode, so Netlify will only be used to preview development of the site.

      Travis CI

      Travis CI is a continuous integration tool that tests and deploys the code you upload to your GitHub repository. Travis will be used in this guide to deploy your Gatsby site to a Linode running Ubuntu 18.04. Testing your website code will not be explored in depth, but the method for integrating unit tests will be introduced.

      The CI/CD Pipeline Sequence

      This guide sets up the following flow of events:

      1. You create a new branch in your local Git repository and make code changes to your Gatsby project.

      2. You push your branch to your GitHub repository and create a pull request.

      3. Netlify automatically creates a preview of the site with a unique URL that can be shared.

      4. Travis CI automatically builds the site in an isolated container and runs any declared tests.

      5. When all tests pass, you merge the PR into the repository’s master branch, which automatically triggers a deployment to your production Linode.

      Before You Begin

      1. Follow the Getting Started guide and deploy a Linode running Ubuntu 18.04.

      2. Complete the Securing Your Server guide to create a limited Linux user account with sudo privileges, harden SSH access, and remove unnecessary network services.

        Note

        This guide is written for a non-root user. Commands that require elevated privileges are prefixed with sudo. If you’re not familiar with the sudo command, visit our Users and Groups guide.

        All configuration files should be edited with elevated privileges. Remember to include sudo before running your text editor.

      3. Configure DNS for your site by adding a domain zone and setting up reverse DNS on your Linode’s IP.

      4. Create a GitHub account if you don’t already have one. GitHub is free for open source projects.

      5. Install Git on your local computer. Later in this guide, Homebrew will be used to install Gatsby on a Mac, so it’s recommended that you also use Homebrew to install Git if you’re using a Mac.

      Prepare Your Production Linode

      Install NGINX

      1. Install NGINX from Ubuntu’s repository on your Linode:

        sudo apt install nginx
        

      Configure NGINX

      1. Delete the default welcome page:

        sudo rm /etc/nginx/sites-enabled/default
        
      2. Create a site configuration file for Gatsby. Replace example.com in the file name and in the file’s contents with your domain name:

        /etc/nginx/conf.d/example.com.conf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        
        server {
            listen       80;
            server_name  example.com;
            #charset koi8-r;
            #access_log  /var/log/nginx/host.access.log  main;
        
            location / {
                root   /usr/share/nginx/html/example.com/public;
                index  index.html index.htm;
            }
        }

        Note

        Replace all future instances of example.com in this guide with your domain name.

      3. The root directive in your NGINX configuration points to a directory named public within /usr/share/nginx/html/example.com/. Later in this guide, Gatsby will be responsible for creating the public directory and building its static content within it (specifically, via the gatsby build command).

        The /usr/share/nginx/html/example.com/ directory does not exist on your server yet, so create it:

        sudo mkdir -p /usr/share/nginx/html/example.com/
        
      4. The Gatsby deployment script that will be introduced later in this guide will run under your limited Linux user. Set your limited user to be the owner of the new document root directory. This ensures the deployment script will be able write your site’s files to it:

        sudo chown $(whoami):$(id -gn) -R /usr/share/nginx/html/example.com/
        
      5. Test your NGINX configuration for errors:

        sudo nginx -t
        
      6. Reload the configuration:

        sudo nginx -s reload
        
      7. Navigate to your Linode’s domain or IP address in a browser. Your Gatsby site files aren’t deployed yet, so you should only see a 404 Not Found error. Still, this error indicates that your NGINX process is running as expected.

      Develop with Gatsby on Your Local Computer

      You will develop with Gatsby on your local computer. This guide walks through creating a simple sample Gatsby website, but more extensive website development is not explored, so review Gatsby’s official documentation afterwards for more information on the subject.

      Install Gatsby

      This section provides instructions for installing Gatsby via Node.js and the Node Package Manager (npm) on Mac and Linux computers. If you are using a Windows PC, read Gatsby’s official documentation for installation instructions.

      1. Install npm on your local computer. If you are running Ubuntu or Debian on your computer, use apt:

        sudo apt install nodejs npm
        

        If you have a Mac, use Homebrew:

        brew install nodejs npm
        
      2. Ensure Node.js was installed by checking its version:

        node --version
        
      3. Install the Gatsby command line:

        sudo npm install --global gatsby-cli
        

      Create a Gatsby Site

      1. Gatsby uses starters to provide a pre-configured base Gatsby site that you can customize and build on top of. This guide uses the Hello World starter. On your local computer, install the Hello World starter in your home directory (using the name example-site for your new project) and navigate into it:

        gatsby new example-site https://github.com/gatsbyjs/gatsby-starter-hello-world
        cd ~/example-site
        
      2. Inspect the contents of the directory:

        ls
        

        You should see output similar to:

          
        LICENSE  node_modules  package.json  package-lock.json  README.md  src
        
        

        The src directory contains your project’s source files. This starter will include the React Javascript component file src/pages/index.js, which will be mapped to our example site’s homepage.

        Gatsby uses React components to build your site’s static pages. Components are small and isolated pieces of code, and Gatsby stores them in the src/pages directory. When your Gatsby site is built, these will automatically become your site’s pages, with paths based on each file’s name.

      3. Gatsby offers a built-in development server which builds and serves your Gatsby site. This server will also monitor any changes made to your src directory’s React components and will rebuild Gatsby after every change, which helps you see your local changes as you make them.

        Open a new shell session (in addition the one you already have open) and run the Gatsby development server:

        cd ~/example-site
        gatsby develop
        
      4. The gatsby develop command will display messages from the build process, including a section similar to the following:

          
        You can now view gatsby-starter-hello-world in the browser.
        
            http://localhost:8000/
        
        

        Copy and paste the http://localhost:8000/ URL (or the specific string displayed in your terminal) into your web browser to view your Gatsby site. You should see a page that displays “Hello World”.

      5. In your original shell session, view the contents of your example-site directory again:

        ls
        
          
            LICENSE  node_modules  package.json  package-lock.json  README.md  src  public
            
        

        You should now see a public directory which was not present before. This directory holds the static files built by Gatsby. Your NGINX server will serve the static files located in the public directory.

      6. Open the src/pages/index.js file in your text editor, add new text between the <div> tags, and save your change:

        src/pages/index.js
        1
        2
        3
        4
        
        import React from "react"
        
        export default () => <div>Hello world and universe!</div>
        
      7. Navigate back to your browser window, where the updated text should automatically appear on the page.

      Version Control Your Gatsby Project

      In the workflow explored by this guide, Git and GitHub are used to:

      • Track changes you make during your site’s development.
      • Trigger the preview, test, and deployment functions offered by Netlify and Travis.

      The following steps present how to initialize a new local Git repository for your Gatsby project, and how to connect it to a central GitHub repository.

      1. Open a shell session on your local computer and navigate to the example-site directory. Initialize a Git repository to begin tracking your project files:

        git init
        

        Stage all the files you’ve created so far for your first commit:

        git add -A
        

        The Hello World starter includes a .gitignore file. Your .gitignore designates which files and directories to ignore in your Git commits. By default, it is set to ignore any files in the public directory. The public directory’s files will not be tracked in this repository, as they can be quickly rebuilt by anyone who clones your repository.

      2. Commit all the Hello World starter files:

        git commit -m "Initial commit"
        
      3. Navigate to your GitHub account and create a new repository named example-site. After the repository is created, copy its URL, which will have the form https://github.com/your-github-username/example-site.git.

      4. In your local computer’s shell session, add the GitHub repository as your local repository’s origin:

        git remote add origin https://github.com/your-github-username/example-site.git
        
      5. Verify the origin remote’s location:

        git remote -v
        
          
        origin	https://github.com/your-github-username/example-site.git (fetch)
        origin	https://github.com/your-github-username/example-site.git (push)
        
        
      6. Push the master branch of your local repository to the origin repository:

        git push origin master
        
      7. View your GitHub account in your browser, navigate to the example-site repository, and verify that all the files have been pushed to it successfully:

        GitHub Initial Commit

      Preview Your Site with Netlify

      In the course of developing a website (or any other software project), a common practice when you’ve finished a new feature and would like to share it with your collaborators is to create a pull request (also referred to as a PR). A pull request is an intermediate step between uploading your work to GitHub (by pushing the changes to a new branch) and later merging it into the master branch (or another release or development branch, according to your specific Git workflow).

      Once connected to your GitHub account, the Netlify service can build a site preview from your PR’s code every time you create a PR. Netlify will also regenerate your site preview if you commit and push new updates to your PR’s branch while the PR is still open. A random, unique URL is assigned to every preview, and you can share these URLs with your collaborators.

      Connect Your GitHub Repository to Netlify

      1. Navigate to the Netlify site and click on the Sign Up link:

        Netlify Home Page

      2. Click on the GitHub button to connect your GitHub account with Netlify. If you used a different version control service, select that option instead:

        GitHub and Netlify connection page

      3. You will be taken to the GitHub site and asked to authorize Netlify to access your account. Click on the Authorize Netlify button:

        GitHub Netlify Authorization

      4. Add your new site to Netlify and continue along with the prompts to finish connecting your repository to Netlify. Be sure to select the GitHub repository created in the previous steps:

        Add site to Netlify

      5. Provide the desired deploy settings for your repository. Unless you are sure you need to change these settings, keep the Netlify defaults:

        Netlify repository settings

        Note

        You can add a netlify.toml configuration file to your Git repository to define more deployment settings.

      Create a Pull Request

      1. In your local Git repository, create a new branch to test Netlify:

        git checkout -b test-netlify
        
      2. On your computer, edit your src/pages/index.js and update the message displayed:

        src/pages/index.js
        1
        2
        3
        4
        
        import React from "react"
        
        export default () => <div>Hello world, universe, and multiverse!</div>
        
      3. Commit those changes:

        git add .
        git commit -m "Testing Netlify"
        
      4. Push the new branch to the origin repository:

        git push origin test-netlify
        
      5. Navigate to the example-site repository in your GitHub account and create a pull request with the test-netlify branch:

        GitHub Compare and Pull Request Banner

      6. After you create the pull request, you will see a deploy/netlify row with a Details link. The accent color for this row will initially be yellow while the Netlify preview is being built. When the preview’s build process is finished, this row will turn green. At that point, you can click on the Details link to view your Gatsby site’s preview.

        Netlify GitHub Preview

        Every time you push changes to your branch, Netlify will provide a new preview link.

      Test and Deploy Your Site with Travis CI

      Travis CI manages testing your Gatsby site and deploying it to the Linode production server. Travis does this by monitoring updates to your GitHub repository:

      • Travis’s tests will run when a pull request is created, whenever new commits are pushed to that pull request’s branch, and whenever a branch is updated on your GitHub repository in general (including outside the context of a pull request).

      • Travis’s deployment function will trigger whenever a pull request has been merged into the master branch (and optionally when merging into other branches, depending on your configuration).

      Connect Your GitHub Repository to Travis CI

      1. Navigate to the Travis CI site and click on the Sign up with GitHub button.

        Note

        Be sure to visit travis-ci.com, not travis-ci.org. Travis originally operated travis-ci.com for paid/private repositories, and travis-ci.org was run separately for free/open source projects. As of May 2018, travis-ci.com supports open source projects and should be used for all new projects. Projects on travis-ci.org will eventually be migrated to travis-ci.com.
      2. You will be redirected to your GitHub account. Authorize Travis CI to access your GitHub account:

        Authorize Travis CI

      3. You will be redirected to your Travis CI account’s page where you will be able to see a listing of all your public repositories. Click on the toggle button next to your Gatsby repository to activate Travis CI for it.

      Configure Travis CI to Run Tests

      Travis’s functions are all configured by adding and editing a .travis.yml file in the root of your project. When .travis.yml is present in your project and you push a commit to your central GitHub respository, Travis performs one or more builds.

      Travis builds are run in new virtualized environments created for each build. The build lifecycle is primarily composed of an install step and a script step. The install step is responsible for installing your project’s dependencies in the new virtual environment. The script step invokes one or more bash scripts that you specify, usually test scripts of some kind.

      1. Navigate to your local Gatsby project and create a new Git branch to keep track of your Travis configurations:

        git checkout -b travis-configs
        
      2. Create your .travis.yml file at the root of the project:

        touch .travis.yml
        

        Note

        Make sure you commit changes at logical intervals as you modify the files in your Git repository.

      3. Open your .travis.yml file in a text editor and add the following lines:

        ~/example-site/.travis.yml
        1
        2
        3
        4
        5
        6
        
        language: node_js
        node_js:
          - '10.0'
        
        dist: trusty
        sudo: false

        This configuration specifies that the build’s virtual environment should be Ubuntu 14.04 (also known as trusty). sudo: false indicates that the virtual environment should be a container, and not a full virtual machine. Other environments are available.

        Gatsby is built with Node.js, so the Travis configuration is set to use node_js as the build language, and to use the latest version of Node (10.0 at the time of this guide’s publication). When Node is specified as the build language, Travis automatically sets default values for the install and script steps: install will run npm install, and script will run npm test. Other languages, like Python, are also available.

      4. The Gatsby Hello World starter provides a package.json file, which is a collection of metadata that describes your project. It is used by npm to install, run, and test your project. In particular, it includes a dependencies section used by npm install, and a scripts section where you can declare the tests run by npm test.

        No tests are listed by default in your starter’s package.json, so open the file with your editor and add a test line to the scripts section:

        package.json
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        
        {
          "name": "gatsby-starter-hello-world",
          "description": "Gatsby hello world starter",
          "license": "MIT",
          "scripts": {
            "develop": "gatsby develop",
            "build": "gatsby build",
            "serve": "gatsby serve",
            "test": "echo 'Run your tests here'"
          },
          "dependencies": {
            "gatsby": "^1.9.277",
            "gatsby-link": "^1.6.46"
          }
        }

        This entry is just a stub to illustrate where tests are declared. For more information on how to test your Gatsby project, review the unit testing documentation on Gatsby’s website. Jest is the testing framework recommended by Gatsby.

      View Output from Your Travis Build

      1. Commit the changes you’ve made and push your travis-configs branch to your origin repository:

        git add .
        git commit -m "Travis testing configuration"
        git push origin travis-configs
        
      2. View your GitHub repository in your browser and create a pull request for the travis-configs branch.

      3. Several rows that link to your Travis builds will appear in your new pull request. When a build finishes running without error, the build’s accent color will turn green:

        GitHub Travis Builds

        Note

        Four rows for your Travis builds will appear, which is more than you may expect. This is because Travis runs your builds whenever your branch is updated, and whenever your pull request is updated, and Travis considers these to be separate events.

        In addition, the rows prefixed by Travis CI - are links to GitHub’s preview of those builds, while rows prefixed with continuous-integration/travis-ci/ are direct links to the builds on travis-ci.com.

        For now, these builds will produce identical output. After the deployment functions of Travis have been configured, the pull request builds will skip the deployment step, while the branch builds will implement your deployment configuration.

      4. Click the Details link in the continuous-integration/travis-ci/push row to visit the logs for that build. A page with similar output will appear:

        Travis Build Logs - First Test

        Towards the end of your output, you should see the “Run your tests here” message from the test stub that you entered in your package.json. If you implement testing of your code with Jest or another library, the output from those tests will appear at this location in your build logs.

        If any of the commands that Travis CI runs in the script step (or in any preceding steps, like install) returns with a non-zero exit code, then the build will fail, and you will not be able to merge your pull request on GitHub.

      5. For now, do not merge your pull request, even if the builds were successful.

      Give Travis Permission to Deploy to Your Linode

      In order to let Travis push your code to your production Linode, you first need to give the Travis build environment access to the Linode. This will be accomplished by generating a public-private key pair for your build environment and then uploading the public key to your Linode. Your code will be deployed over SSH, and the SSH agent in the build environment will be configured to use your new private key.

      The private key will also need to be encrypted, as the key file will live in your Gatsby project’s Git repository, and you should never check a plain-text version of it into version control.

      1. Install the Travis CLI, which you will need to generate an encrypted version of your private key. The Travis CLI is distributed as a Ruby gem:

        On Linux:

        sudo apt install ruby ruby-dev
        sudo gem install travis
        

        On macOS:

        sudo gem install travis
        

        On Windows: Use RubyInstaller to install Ruby and the Travis CLI gem.

      2. Log in to Travis CI with the CLI:

        travis login --com
        

        Follow the prompts to provide your GitHub login credentials. These credentials are passed directly to GitHub and are not recorded by Travis. In exchange, GitHub returns a GitHub access token to Travis, after which Travis will provide your CLI with a Travis access token.

        Note

      3. Inside the root of your local example-site Git repository, create a scripts directory. This will hold files related to deploying your Gatsby site:

        mkdir scripts
        
      4. Generate a pair of SSH keys inside the scripts directory. The key pair will be named gatsby-deploy so that you don’t accidentally overwrite any preexisting key pairs. Replace your_email@example.com with your email address. When prompted for the key pair’s passphrase, enter no passphrase/leave the field empty:

        ssh-keygen -t rsa -b 4096 -C "your_email@example.com" -f scripts/gatsby-deploy
        

        Two files will be created: gatsby-deploy (your private key) and gatsby-deploy.pub (your public key).

      5. Add the location of the gatsby-deploy file to your project’s .gitignore file. This will ensure that you do not accidentally commit the secret key to your central repository:

        .gitignore
        1
        2
        3
        
        # Other .gitignore instructions
        # [...]
        scripts/gatsby-deploy
      6. Encrypt your private key using the Travis CLI:

        cd scripts && travis encrypt-file gatsby-deploy --add --com
        
      7. You should now see a gatsby-deploy.enc file in your scripts directory:

        ls
        
          
            gatsby-deploy		gatsby-deploy.enc	gatsby-deploy.pub
        
        
      8. The --add flag from the previous command also told the Travis CLI to add a few new lines to your .travis.yml file. These lines decrypt your private key and should look similar to the following snippet:

        .travis.yml
        1
        2
        3
        
        before_install:
        - openssl aes-256-cbc -K $encrypted_9e3557de08a3_key -iv $encrypted_9e3557de08a3_iv
          -in gatsby-deploy.enc -out gatsby-deploy -d


        About the openssl command and Travis build variables

        The second line (starting with -in gatsby-deploy.enc) is a continuation of the first line, and -in is an option passed to the openssl command. This line is not its own item in the before_install list.

        The openssl command accepts the encrypted gatsby-deploy.enc file and uses two environment variables to decrypt it, resulting in your original gatsby-deploy private key. These two variables are stored in the Settings page for your repository on travis-ci.com. Any variables stored there will be accessible to your build environment:

        Travis Environment Variables

      9. Edit the lines previously added by the travis encrypt-file command so that gatsby-deploy.enc and gatsby-deploy are prefixed with your scripts/ directory:

        .travis.yml
        1
        2
        3
        
        before_install:
        - openssl aes-256-cbc -K $encrypted_9e3557de08a3_key -iv $encrypted_9e3557de08a3_iv
          -in scripts/gatsby-deploy.enc -out scripts/gatsby-deploy -d
      10. Continue preparing the SSH agent in your build environment by adding the following lines to the before_install step, after the openssl command. Be sure to replace 192.0.2.2 with your Linode’s IP address:

        ~/example-site/.travis.yml
        1
        2
        3
        4
        5
        6
        7
        8
        
        before_install:
        - openssl aes-256-cbc -K $encrypted_9e3557de08a3_key -iv $encrypted_9e3557de08a3_iv
          -in scripts/gatsby-deploy.enc -out scripts/gatsby-deploy -d
        - eval "$(ssh-agent -s)"
        - cp scripts/gatsby-deploy ~/.ssh/gatsby-deploy
        - chmod 600 ~/.ssh/gatsby-deploy
        - ssh-add ~/.ssh/gatsby-deploy
        - echo -e "Host 192.0.2.2ntStrictHostKeyChecking non" >> ~/.ssh/config
      11. Travis CI can add entries to the build environment’s ~/.ssh/known_hosts prior to deploying your site. Insert the following addons step prior to the before_install step in your .travis.yml. Replace 192.0.2.2 with your Linode’s IP address:

        ~/example-site/.travis.yml
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        
        # [...]
        dist: trusty
        sudo: false
        
        addons:
          ssh_known_hosts:
            - 192.0.2.2
        
        before_install:
        # [...]
      12. From your local computer, upload your Travis environment’s public key to the home directory of your limited Linux user on your Linode. Replace example_user with your Linode’s user and 192.0.2.2 with your Linode’s IP address:

        scp ~/example-site/scripts/gatsby-deploy.pub example_user@192.0.2.2:~/gatsby-deploy.pub
        
      13. Log in to your Linode (using the same user that the key was uploaded to) and copy the key into your authorized_keys file:

        mkdir -p .ssh
        cat gatsby-deploy.pub | tee -a .ssh/authorized_keys
        

      Create a Deployment Script

      1. Update your .travis.yml to include a deploy step. This section will be executed when a pull request is merged into the master branch. Add the following lines below the before_install step, at the end of the file:

        ~/example-site/.travis.yml
        1
        2
        3
        4
        5
        6
        
        deploy:
        - provider: script
          skip_cleanup: true
          script: bash scripts/deploy.sh
          on:
            branch: master

        The instructions for pushing your site to your Linode will be defined in a deploy.sh script that you will create.


        Full contents of your Travis configuration

        The complete and final version of your .travis.yml file should resemble the following:

        ~/example-site/.travis.yml
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        
        language: node_js
        node_js:
        - "10.0"
        
        dist: trusty
        sudo: false
        
        addons:
          ssh_known_hosts:
          - 192.0.2.2
        
        before_install:
        - openssl aes-256-cbc -K $encrypted_07d52615a665_key -iv $encrypted_07d52615a665_iv
          -in scripts/gatsby-deploy.enc -out scripts/gatsby-deploy -d
        - eval "$(ssh-agent -s)"
        - cp scripts/gatsby-deploy ~/.ssh/gatsby-deploy
        - chmod 600 ~/.ssh/gatsby-deploy
        - ssh-add ~/.ssh/gatsby-deploy
        - echo -e "Host 192.0.2.2ntStrictHostKeyChecking non" >> ~/.ssh/config
        
        deploy:
        - provider: script
          skip_cleanup: true
          script: bash scripts/deploy.sh
          on:
            branch: master
      2. From your local example-site Git repository, create a deploy.sh file in the scripts directory and make it executable:

        touch scripts/deploy.sh
        chmod +x scripts/deploy.sh
        
      3. Open your deploy.sh file in your text editor and add the following lines. Replace all instances of example_user with your Linode’s user, and replace 192.0.2.2 with your Linode’s IP:

        scripts/deploy.sh
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        
        #!/bin/bash
        set -x
        
        gatsby build
        
        # Configure Git to only push the current branch
        git config --global push.default simple
        
        # Remove .gitignore and replace with the production version
        rm -f .gitignore
        cp scripts/prodignore .gitignore
        cat .gitignore
        
        # Add the Linode production server as a remote repository
        git remote add production ssh://example_user@192.0.2.2:/home/example_user/gatsbybare.git
        
        # Add and commit all the static files generated by the Gatsby build
        git add . && git commit -m "Gatsby build"
        
        # Push all changes to the Linode production server
        git push -f production HEAD:refs/heads/master

        The deploy script builds the Gatsby static files (which are placed inside the public directory inside your repository) and pushes them to your Linode. Specifically, this script:

        • Commits the newly-built public directory to the Travis build environment’s copy of your Git repository.
        • Pushes that commit (over the SSH protocol) to a remote repository on your Linode, which you will create in the next section of this guide.

        Note

        Remember that because these instructions are executed in an isolated virtual environment, the git commit that is run here does not affect the repository on your local computer or on GitHub.

      4. You may recall that you previously updated your .gitignore file to exclude the public directory. To allow this directory to be committed in your build environment’s repository (and therefore pushed to your Linode), you will need to override that rule at deploy time.

        From the root of your local Gatsby project, copy your .gitignore to a new scripts/prodignore file:

        cp .gitignore scripts/prodignore
        

        Open your new prodignore file, remove the public line, and save the change:

        scripts/prodignore
        1
        2
        3
        
        .cache/
        public # Remove this line
        yarn-error.log

        The deploy.sh script you created includes a line that will copy this scripts/prodignore file into your repository’s root .gitgnore, which will then allow the script to commit the public directory.

      Prepare the Remote Git Repository on Your Linode

      In the previous section you completed the configuration for the Travis deployment step. In this section, you will prepare the Linode to receive Git pushes from your deployment script. The pushed website files will then be served by your NGINX web server.

      1. SSH into your Linode (under the same the user that holds your Travis build environment’s public key). Create a new directory inside your home folder named gatsbybare.git:

        mkdir ~/gatsbybare.git
        
      2. Navigate to the new directory and initialize it as a bare Git repository:

        cd ~/gatsbybare.git
        git init --bare
        

        A bare Git repository stores Git objects and does not maintain working copies (i.e. file changes that haven’t been committed) in the directory. Bare repositories provide a centralized place where users can push their changes. GitHub is an example of a bare Git repository. The common practice for naming a bare Git repository is to end the name with the .git extension.

      3. Configure the Git directory to allow linking two repositories together:

        git config receive.denyCurrentBranch updateInstead
        
      4. Your Travis build environment will now be able to push files into your Linode’s Git repository, but the files will not be located in your NGINX document root. To fix this, you will use the hooks feature of Git to copy your website files to the document root folder. Specifically, you can implement a post-receive hook that will run after every push to your Linode’s repository.

        In your Linode’s Git repository, create the post-receive file and make it executable:

        touch hooks/post-receive
        chmod +x hooks/post-receive
        
      5. Add the following lines to the post-receive file. Replace example.com with your domain name, and replace example_user with your Linode’s user:

        hooks/post-receive
        1
        2
        
        #!/bin/sh
        git --work-tree=/usr/share/nginx/html/example.com --git-dir=/home/example_user/gatsbybare.git checkout -f

        This script will check out the files from your Linode repository’s master branch into your document root folder.

        Note

        While a bare Git repository does not keep working copies of files within the repository’s directory, you can still use the --work-tree option to check out files into another directory.

      Deploy with Travis CI

      All of the test and deployment configuration work has been completed and can now be executed:

      1. Commit all remaining changes to your travis-configs branch and push them up to your central GitHub repository:

        git add .
        git commit -m "Travis deployment configuration"
        git push origin travis-configs
        
      2. Visit the pull request you previously created on GitHub for your travis-configs branch. If you visit this page shortly after the git push command is issued, the new Travis builds may still be in progress.

      3. After the linked continuous-integration/travis-ci/pr pull request Travis build completes, click on the corresponding Details link. If the build was successful, you should see the following message:

          
        Skipping a deployment with the script provider because the current build is a pull request.
        
        

        This message appears because pull request builds skip the deployment step.

      4. Back on the GitHub pull request page, after the linked continuous-integration/travis-ci/push branch build completes, click on the corresponding Details link. If the build was successful, you should see the following message:

          
        Skipping a deployment with the script provider because this branch is not permitted: travis-configs
        
        

        This message appears because your .travis.yml restricts the deployment script to updates on the master branch.

      5. If your Travis builds failed, review the build logs for the reason for the failure.

      6. If the builds succeeded, merge your pull request.

      7. After merging the pull request, visit travis-ci.com directly and view the example-site repository. A new Travis build corresponding to your Merge pull request commit will be in progress. When this build completes, a Deploying application message will appear at the end of the build logs. This message can be expanded to view the complete logs for the deploy step.

      8. If your deploy step succeeded, you can now visit your domain name in your browser. You should see the message from your Gatsby project’s index.js.

      Troubleshooting

      If your Travis builds are failing, here are some places to look when troubleshooting:

      • View the build logs for the failed Travis build.
      • Ensure all your .sh scripts are executable, including the Git hook on the Linode.
      • Test the Git hook on your Linode by running bash ~/gatsbybare.git/hooks/post-receive.
      • If you encounter permissions issues, make sure your Linode user can write files to your document root directory.
      • To view the contents of the bare Git repository, run git ls-tree --full-tree -r HEAD.

      Next Steps

      Read the Gatsby.js Tutorial to learn how to build a website with Gatsby.

      Join our Community

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link