Using Codeship to Deploy to sloppy.io
This article was originally published on sloppy.io by Mike Michel. With their kind permission, we’re sharing it here for Codeship readers.
In this post, I will show you how to build a CI/CD pipeline with Codeship and sloppy.io. As an example app, I will use hackathon-starter, which is a great boilerplate to start new projects.
hackathon-starter comes with an MVC project structure, bootstrap 3, CSRF protection, and more. If you want to use your own app, skip the hackathon part and carry on.
Okay, let’s get started.
Clone the hackathon repository and cd into your new working directory:
git clone --depth=1 https://github.com/sahat/hackathon-starter.git myproject cd myproject
Create a docker-compose-dev.yml
file with the following content:
version: '2' services: web: image: node:6.1 volumes: - ./:/usr/src/app working_dir: /usr/src/app command: sh -c 'npm install; npm install -g nodemon ; nodemon -e js,jade app.js' ports: - "80:3000" depends_on: - mongo networks: - all environment: MONGODB_URI: "mongodb://mongo:27017/hackathon" mongo: image: mongo:3 command: mongod --smallfiles networks: - all networks: all:
Check this blog post if you want to know what happens in the compose file.
Fire it up with:
docker-compose -f docker-compose-dev.yml up
and point your browser to http://ip-where-you-started-docker-compose
. hackathon-starter is up, running, and ready for your changes, so let’s do a simple one.
Open views/home.pug
and and change the headline in line 3:
h1 Hackathon Starter with codeship.io
By saving the file, you will notice nodemon reloading the app. If you reload the browser window, you will see the changes too.
Let’s say we are done developing our new app and want to create a deploy-ready container. First, we need to build our own Docker image. Create a file called Dockerfile
inside your working directory:
FROM node:6.1.0 RUN mkdir -p /usr/src/app WORKDIR /usr/src/app COPY . /usr/src/app/ RUN npm install CMD [ "node", "app.js" ]
Build it (with your own dockerhubname):
docker build -t yourdockerhubname/hackathon-starter:0.1 .
Then, create a docker-compose.yml
file to test if your just-build image is running as expected.
version: '2' services: web: image: yourdockerhubname/hackathon-starter:0.1 ports: - "80:3000" depends_on: - mongo networks: - all environment: MONGODB_URI: "mongodb://mongo:27017/hackathon" mongo: image: mongo:3 command: mongod --smallfiles networks: - all networks: all:
Finally, fire it up. This time we don’t need -f
because by default docker-compose.yml
is started.
docker-compose up
If everything is fine, push your image to the Docker Hub. Again, don’t forget to replace your dockerhubname.
docker push yourdockerhubname/hackathon-starter:0.1
Now everybody is able to start your app locally using the docker-compose.yml
file and a simple docker-compose up
.
Note that docker-compose-dev.yml
is doing npm install
and npm install -g nodemon
every time you start it. If you don’t want this to happen, simply remove this section from the command line.
command: sh -c 'npm install -g nodemon ; nodemon -e js,jade app.js'
Let’s deploy your hackathon project to sloppy.io now.
Create the following sloppy.yml file but change the image section to your recently uploaded image name and choose your own free .sloppy.zone domain (also at ROOT_URL):
version: "v1" project: "hackathon-starter" services: frontend: node: image: "mikemichel/hackathon-starter:0.1" instances: 1 mem: 512 domain: myhackathon.sloppy.zone port: 3000 env: - MONGODB_URI: "mongodb://mongodb.backend.hackathon-starter/hackathon" - ROOT_URL: "https://myhackathon.sloppy.zone" dependencies: - "../backend/mongodb" backend: mongodb: image: "mongo" cmd: "mongod --smallfiles" instances: 1 mem: 512 volumes: - path: "/data/db" - path: "/data/configdb"
And start it with the sloppy.io CLI:
sloppy start sloppy.yml +----------+--------+--------+--------------+ | SERVICE | # APPS | STATUS | TOTAL MEMORY | +----------+--------+--------+--------------+ | frontend | 1 | 0 / 1 | 512 MiB | | backend | 1 | 0 / 1 | 512 MiB | +----------+--------+--------+--------------+
Check the status using the sloppy.io UI:
And open your first version in the browser, clicking the link icon next to node.
How to Create a Rolling Update with Codeship
What we want to achieve is that every push to the controller branch of our own git repo will do a rolling update to sloppy.io. As we cloned our git repo from hackathon-starter, we now have all the commits from the original repo in the history and our clone still points to the original repo, so let’s fix this first.
Create a new repo in GitHub (you have to be logged in). I will name mine hackathon. Then make the needed changes for the cloned repo on the command line:
cd myproject rm -R .git # start with a clean git base git init # initalize a new git repository git add . # add all files for commit git commit -m "initial commit" git remote add origin https://github.com/YourGithubName/yourJustCreatedRepoName.git # use your own created repo here git push -u origin master # push it
Now let’s configure codeship.io to do the following when we push changes to our git repo:
Pull code and do some tests.
Build a new container and push it to Docker Hub.
Deploy the new version to sloppy.io.
Create a new project:
Connect it to your GitHub repo:
Choose Basic Infrastructure and then node.js as technology stack:
Save it and go back to the dashboard. Codeship will now pull and test our code, but what if we want more? We need a new Docker image from our code in the Docker Hub, and it should replace the version already running at sloppy.io.
First, we will switch our project to the Docker infrastructure by changing it in the general project settings:
An AES key is now displayed. Copy and save it into a file called codeship.aes
(gitignore?) inside your git directory. Now download the Codeship Jet CLI. This tool is used to create encrypted sensitive information like the Docker Hub login, which is needed by Codeship to be able to push to your Docker repo.
After installation, log in into your Docker Hub account using docker login
and use Jet (still inside your git repo) and encrypt your credentials:
docker login jet encrypt ${HOME}/.docker/config.json dockercfg.encrypted
There should now be a dockercfg.encrypted
, which is used later by Codeship to push the new Docker image into your Docker Hub repo.
We also want to encrypt the sloppy.io API token when Codeship deploys the new image. We will do this by encrypting the token as an environment variable. Following Codeship's documentation, we create a file sloppytoken.env
with your own token from https://admin.sloppy.io/account/tokens (skip the export part!):
SLOPPY_APITOKEN=eyJ0eXAiOiJKV1QiLCJhbGcGVsODExQGdtYWlsLmNvbSIsInJldm9rYWJsZSI6dHJ1ZSwiaWF0IjoxNDc5ODg5MTk1LCJhdWQiOiI3RXdpZTBXdmY1VFZORjRCWEo0ek5HZk9qNjkkj9GpGSlVyQyJ9.YoIbDScrFD4CbMFGyXgnc1vj3B-kRiOcEFtXtuPrLYE
Encrypt it:
jet encrypt sloppytoken.env sloppytoken.env.encrypted
sloppytoken.env.encrypted
will be created, so we should delete sloppytoken.env
. We don`t want to push our token to GitHub, right?!
Now everything is saved, and we can configure the actual build and deploy jobs. This is done in Codeship via Services and Steps. In short, Services is where you configure each service needed to run to CI/CD and builds with Codeship. During the build, these services will be used to run the testing steps you’ve defined in your codeship-steps.yml
process.
Let’s create the codeship-services.yml
file:
app: build: image: mikemichel/hackathon-starter dockerfile_path: Dockerfile encrypted_env_file: sloppytoken.env.encrypted
Here we define a build with the image output name mikemichel/hackathon-starter
. The Dockerfile is used in the current build directory, and our encrypted sloppy.io token login is defined for the following codeship-steps.yml
that we create now:
- service: app type: push image_name: mikemichel/hackathon-starter image_tag: "{{ .CommitID }}" registry: https://index.docker.io/v1/ encrypted_dockercfg_path: dockercfg.encrypted - service: app command: ./deploy.sh
The first block defines the push to Docker Hub and that we want to use the git commit ID as an image tag. The second part is about the deployment to sloppy.io via deploy.sh
, which we will create now:
#!/bin/bash #set -e SLOPPY_APITOKEN=${SLOPPY_APITOKEN} # install latest sloppy.io cli curl -L https://files.sloppy.io/sloppy-`uname -s`-`uname -m` > /usr/local/bin/sloppy chmod +x /usr/local/bin/sloppy # deploy new image echo "Deploying new image using the CLI" sloppy change -img mikemichel/hackathon-starter:$CI_COMMIT_ID hackathon-starter/frontend/node
deploy.sh
is a bash script, so let’s make it executable with chmod +x deploy.sh
.
It’s a simple bash script, installing the sloppy.io CLI and then using the change command to update your running app to the recently created image. You can find more info about services and steps here.
Now save, commit, and push the changes to your git repo, and Codeship will start working. Follow the process live in the Codeship UI.
git add . git commit -am "changed header" git push
The last step (deploy.sh
) will trigger the deployment. Check the sloppy.io UI:
You will see that only the node container is updated and the version for the node app will change to the git commit ID. Every git push will trigger this flow. This will also create a new version in sloppy.io that you can always go back to. Just click DEPLOYED and choose a version for a rollback.
Stay up to date
We'll never share your email address and you can opt out at any time, we promise.