Setup web-page screenshots within a minute
Tags: showdev, ruby, go, kubernetes
Published: 2020-04-06 09:40:43

---
title: Setup web-page screenshots within a minute
published: true
description: Introduce Kubernetes-ready simple screenshot web service
tags: #showdev #ruby #go #kubernetes
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/gw2ok407nh94p9094l81.png
---

For many years [PhantomJS](https://phantomjs.org/) is used to generate a web-page screenshot.  As we have a Ruby web-application on Kubebernetes, it brought some inconveniences: we had to install NodeJs and PhantomJS rights into the main Ruby Docker image:
```
# Phantomjs is installed via npm to avoid HUGE dependencies such as QT and others.
RUN npm install phantomjs-prebuilt \
  && ln -s /node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs /usr/local/bin/phantomjs \
  && rm -rf /tmp/phantomjs

COPY ./fonts/Helvetica.ttf /usr/share/fonts/truetype/Helvetica.ttf
```

It causes all the application instances, like web, sidekiq, and others, had these low-level dependencies installed even if they did not need to generate screenshots.

[For some time](https://semaphoreci.com/blog/2018/03/27/phantomjs-is-dead-use-chrome-headless-in-continuous-integration.html) PhantomJS are not supported anymore. The new alternative is to use Google Chrome within the "headless" mode, a great example of doing it from the command line:

```
google-chrome --headless --window-size=1180,768 --screenshot=/tmp/screenshot.png https://amplifr.com/en
```

We need to get google-chrome installed to a machine, so using this command rights from the ruby code doesn't change anything fundamentally.

That is why I decided to extract it into separated HTTP based micro-service for capturing web-page and returning an image.

Here it is [https://github.com/dsalahutdinov/screenshot](https://github.com/dsalahutdinov/screenshot)
It could be touched with `curl`:

```
curl --output screenshot.png http://screenshot.local/screenshot\?width\=1180\&height\=768\&url\=https://amplifr.com/en
```
Or with browser as well:

![Generated screenshot](https://dev-to-uploads.s3.amazonaws.com/i/pghlk41nmkn7ftl07h4v.png)

## Internals

Internally it is simple HTTP-wrapper for running `Chrome` and return resulting image file. Nothing more on it. Screenshot tool is Kubernetes-ready, and you can get it up in a minute by running `kubectl` or using predefined `helm`-chart.

## Use Helm Chart

The predefined helm-chart is located [here](https://github.com/dsalahutdinov/screenshot-helm). This repo also works as a helm-repository on top of Github pages. Add the repository to your helm settings:

```sh
$ helm repo add screenshot-helm https://dsalahutdinov.github.io/screenshot-helm/
"screenshot-helm" has been added to your repositories
```
And deploy the chart into current Kubernetes cluster:
```sh
$ helm install screenshot-helm/screenshot --name screenshot --namespace screenshot

NAME:   screenshot
LAST DEPLOYED: Sat Apr  4 16:59:02 2020
NAMESPACE: screenshot
STATUS: DEPLOYED

RESOURCES:
==> v1/Deployment
NAME         AGE
screenshot  1s

==> v1/Pod(related)
NAME                      AGE
screenshot-76948b-rrq77  1s

==> v1/Service
NAME         AGE
screenshot  1s
```

Since then, service will run as "internal" without any ingress resources. You can access it within the cluster by its internal DNS name, [release].[namespace].kubernetes.local, or with just short name [release].[namespace]:

```sh
curl --output screenshot.png \
     http://screenshot.screenshot/screenshot/?width=1180&height=768&url=https://amplifr.com/en
```

## Run on Minikube
Here is the manual for running screenshot service into [Minikube](https://github.com/kubernetes/minikube) local cluster with using "external" domain name `screenshot.local`:

```
# starts minikube
minikube start

# gets minikube ip address and adds it as screenshot.local domain address
echo "$(minikube ip) screenshot.local" | sudo tee -a /etc/hosts

# adds helm repository
$ helm repo add screenshot-helm 

# installs screenshot service with the enabled ingress
$ helm install screenshot-helm/screenshot \
  --name screenshot \
  --namespace screenshot \
  --set ingress.enabled=True \
  --set ingress.hosts\[0\].host=screenshot.local \
  --set ingress.hosts\[0\].paths\[0\]=/screenshot

NAME:   screenshot
LAST DEPLOYED: Mon Apr  6 10:51:54 2020
NAMESPACE: screenshot
STATUS: DEPLOYED

RESOURCES:
==> v1/Deployment
NAME        AGE
screenshot  0s

==> v1/Pod(related)
NAME                         AGE
screenshot-58dd688598-ml9nw  0s

==> v1/Service
NAME        AGE
screenshot  0s

==> v1/ServiceAccount
NAME        AGE
screenshot  0s

==> v1beta1/Ingress
NAME        AGE
screenshot  0s


NOTES:
1. Get the application URL by running these commands:
  http://screenshot.local/screenshot
```

After the start, service will be available to access with `amplifr.local` domain. Other supported options of helm-chart, like resources, tls, affinity you can find [here](https://github.com/dsalahutdinov/screenshot-helm/blob/master/values.yaml).

## Usage

Using ruby is very straightforward:

```ruby
options = {
  height: 1024, width: 768, url: 'https://amplifr.com/en'
}
response = Faraday.new(
  'http://screenshot.screenshot/screenshot?' + options.map { |k, v| "#{k}=#{v}" }.join("&")
).get

File.open('screenshot.png', "wb") {  |f| f.write(response.body) }
```

## Conclusion

The `screenshot` tool is straightforward and solves the simple, practical task - web-page screenshot generation. You can run into a Kubernetes cluster in a minute if you would need a web-page screenshot generation one day.