Dockerイメージについて(メモ)

Dockerイメージとは

Dockerイメージ

  • コンテナ実行に必要なファイルをまとめたファイルシステム
  • AUFSなどの特殊なファイルシステムが使用される
    AUFSとはストレージドライバーでHDなどにストレージのデータを書き込むためのソフトウェアのこと。
    Dockerで使用できるストレージドライバーの一種。
    レイヤーという階層構造で特殊なファイルシステム(らしい)
  • イメージ上のデータはレイヤーで構成され読み取り専用

Dcokerイメージのファイルシステム

文章だけではわかりづらいが、Dockerイメージは階層構造でデータが管理されている。
各層のことをレイヤーと呼ぶ。
基本的にコマンドを実行するたびに積み上げていく仕組みとなっている。
レイヤーは全て読み取り専用となる。

Dockerイメージを基にコンテナを起動すると、新たに読み書き可能なコンテナレイヤーという層が作られる。
このコンテナレイヤーでファイルの追加削除やパッケージの追加や削除を行い、それをもとにイメージを作成することも可能。
ただし、過去のレイヤーで削除したファイルなど、追加時点のレイヤーには残ってしまうため、イメージ全体のサイズは変わらない。
Dockerのメリットである、軽量ですぐに環境を立ち上げられるからかけ離れてしまう。

複数のイメージで継承関係を作れる

CentOSのベースイメージを持ったイメージにRubyのイメージを継承させ、CentOSRubyのレイヤーを一つのイメージにまとめられる。
さらにRailsのイメージを継承させて、CentOS,Ruby,Railsのまとまったイメージを作れる。
同じDockerイメージを継承するメリットとしては、
CentOS,Rubyがまとまったイメージ
CentOS,MySQLがまとまったイメージ
①と②ともにCentOSは同じなので、CentOSは同じデータを利用してくれる。
同じレイヤーを使用している場合、同じレイヤーのデータを参照してくれる。
そのためレイヤーがダブることなく、イメージサイズが小さくなりやすい。

ローカル上にダウンロードしているDockerイメージ一覧表示

$ docker images
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
hello-world       latest    feb5d9fea6a5   3 months ago   13.3kB
sample/webrick    latest    2ffdacbd6685   4 months ago   864MB
ruby              2.7       89699f4d76cf   4 months ago   864MB
docker/whalesay   latest    6b362a9f73eb   6 years ago    247MB

左から順に
REPOSITORY・・・どのリポジトリからダウンロードしたかものを表しています。
TAG・・・どのタグをダウンロードしたのか確認できる
IMAGE ID・・・イメージを識別するためのID
CREATED・・・いつ作成したか
SIZE・・・サイズ

イメージにタグ付を剃るコマンド

ローカル上に存在するイメージのみ可能。
まずエイリアスとするパターン

$ docker tag docker/whalesay test_whalesay
  • tag・・・タグ付けするサブコマンド
  • docker/whalesay・・・元となるイメージ名
  • test_whalesay・・・新しいイメージ名

実行後

$ docker images
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
hello-world       latest    feb5d9fea6a5   3 months ago   13.3kB
sample/webrick    latest    2ffdacbd6685   4 months ago   864MB
ruby              2.7       89699f4d76cf   4 months ago   864MB
test_whalesay     latest    6b362a9f73eb   6 years ago    247MB // 増えた
docker/whalesay   latest    6b362a9f73eb   6 years ago    247MB


タグ付は上記のコマンドに:TAGとすればできる。

$ docker tag docker/whalesay test_whalesay:ver1

$ doker images
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
hello-world       latest    feb5d9fea6a5   3 months ago   13.3kB
sample/webrick    latest    2ffdacbd6685   4 months ago   864MB
ruby              2.7       89699f4d76cf   4 months ago   864MB
docker/whalesay   latest    6b362a9f73eb   6 years ago    247MB
test_whalesay     latest    6b362a9f73eb   6 years ago    247MB
test_whalesay     ver1      6b362a9f73eb   6 years ago    247MB // ここ

IMAGE IDが同じなので、ショートカット的な状態。

イメージの詳細情報を表示するコマンド

$ docker inspect test_whalesay
  • inspect・・・イメージの詳細情報を表示するサブコマンド
  • test_whalesay・・・対象のイメージ名かイメージIDでも可能
    たくさんの情報が出てくるので割愛

ローカルのイメージを削除する方法

$ docker rmi docker/whalesay
  • rmi・・・イメージの削除をするサブコマンド
  • test_whalesay・・・対象のイメージ名かイメージIDでも可能
$ docker rmi -f docker/whalesay
  • -f・・・矯正削除する場合に-fをつける
    すでに削除したいイメージが含まれた状態で作成されたコンテナが存在する場合に、使用する。
    またはコンテナを削除してからイメージを削除する方法もある。
$ docker rmi docker/whalesay
Untagged: docker/whalesay:latest
Untagged: docker/whalesay@sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b

$ docker images
REPOSITORY       TAG       IMAGE ID       CREATED        SIZE
hello-world      latest    feb5d9fea6a5   3 months ago   13.3kB
sample/webrick   latest    2ffdacbd6685   4 months ago   864MB
ruby             2.7       89699f4d76cf   4 months ago   864MB
test_whalesay    latest    6b362a9f73eb   6 years ago    247MB
test_whalesay    ver1      6b362a9f73eb   6 years ago    247MB

本家のwhalesayがなくなりました。

イメージを取得(pull)するコマンド

$ docker pull docker/whalesay
  • pull・・・イメージの削除をするサブコマンド
  • docker/whalesay・・・対象のイメージ名
    Docker Hub上にあるイメージを取得してくるコマンド
    タグを指定しない場合、latestタグを取得してくるが、必ずしも最新バージョンがlatestであるということではない点を注意する必要がある。
$ docker pull docker/whalesay
Using default tag: latest
latest: Pulling from docker/whalesay
Image docker.io/docker/whalesay:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
e190868d63f8: Already exists
909cd34c6fd7: Already exists
0b9bfabab7c1: Already exists
a3ed95caeb02: Already exists
00bf65475aba: Already exists
c57b6bcc83e3: Already exists
8978f6879e2f: Already exists
8eed3712d2cf: Already exists
Digest: sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b
Status: Downloaded newer image for docker/whalesay:latest
docker.io/docker/whalesay:latest

$ docker images
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
hello-world       latest    feb5d9fea6a5   3 months ago   13.3kB
sample/webrick    latest    2ffdacbd6685   4 months ago   864MB
ruby              2.7       89699f4d76cf   4 months ago   864MB
docker/whalesay   latest    6b362a9f73eb   6 years ago    247MB // 増えてる
test_whalesay     latest    6b362a9f73eb   6 years ago    247MB
test_whalesay     ver1      6b362a9f73eb   6 years ago    247MB

Docker動作確認(Docker Desktop)

Dockerの動作確認

動作確認前に必要なもの

  • Docker Desktopのインストール
  • ターミナル

コマンド

$  docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sa256:975f4b14f326b05db86e16de00144f9c12257553bba9484fed41f9b6f2257800
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Hello form Docker!と出れば成功

$ docker run hello-world hello
  • docker
    dockerコマンド
  • run
    サブコマンド
  • hello-world
    イメージの指定

流れ

①DockerクライアントがDockerデーモンへhello-worldのイメージを取ってきてと指示する。
②Dockerデーモンがインターネットを通じてDocker Hubへ頼まれたイメージを取りに行く。
③DockerデーモンがDockerクライアントへ取得したイメージをPC上へ保存して、実行をする
PC上にイメージが存在する場合はイメージを取りに行かず、Dockerデーモンがイメージを実行する。

docker runのコマンドは複数コマンドを実行している

$ docker run hello-world hello
// docker pull: イメージの取得
// docker create: コンテナの作成
// docker start: コンテナの起動

docker run は上記3つのコマンドを一括して行っている

Docker Hubとは

  • Dockerイメージのレジストリサービス
  • Dockerイメージの公開、検索、ダウンロードをすることができる
    Docker Hub
    公式が提供しているイメージや、公式ではない作成されたイメージなどが提供されている。
    自身でもアップ可能。
    使用する場合はなるべく公式のイメージを選んだほうがよさそうだが、信頼できそうな作成者のものかどうかを調べて使うのもよさそう。
    公式かどうか判断は画像のOfficial Imageがあるかどうか

    f:id:zare926:20220115072903p:plain

イメージのタグ付

Docker Hubのイメージの中にTagsというタブがあり、その中でバージョンなどのタグを指定できる。
タグはイメージの後ろに:で区切って指定をする。

$ docker run hello-world hello

上記の場合だとタグをつけていないので、自動的にlatestタグのイメージがダウンロードされている。

$ docker run hello-world hello:latest

でも同じ結果を得られる

Docker入門メモ

Dockerとは

  • コンテナ型仮想環境を作成、実行、管理するためのプラットフォーム
  • Dockerのソフトウェアを使い、素早くコンテナを起動して様々なアプリを実行することができる
  • 異なる設定環境のPCでも簡単に同じ仮想環境を再現できる
  • DockerはGo言語で書かれている

Dockerの用語

Dockerイメージ

Dockerコンテナを作成するための雛形となるもの。
Dockerイメージは、アプリケーション、ライブラリ、設定ファイルなど、アプリケーションを実行するのに必要なものを一式にまとめたもの。
出来上がったアプリケーションをDockerイメージとして保存して、別のサーバーへ持っていくことで同じ環境を別のサーバーでも再現することが可能

Dockerコンテナ

Dockerイメージをもとに作成されるコンテナ型仮想環境のことをDockerコンテナ、またはコンテナと呼ぶ
イメージからコンテナを作成することで、何度でも同じ仮想環境を作成することができる
コンテナを起動することで、イメージにセットアップしたアプリケーションの機能を提供することができる。

Docker Hub

Dockerイメージを保存するための機能などを提供しているサービス。
別の方が作成したイメージもダウンロードでき、コンテナとして動かすことができる
Docker Hubのようなイメージを補完できる機能を持ったものをレジストリと呼ぶ

ユースケース

  • アプリケーション開発
  • 検証環境、本番環境
  • Webサーバー、DBサーバーの構築
  • その他のミドルウェアの環境設定

Dockerを使うメリット

  • プログラムの実行環境を素早く立ち上げられる
  • 再現性のある環境を用意できる、違うPCやサーバー間で動かす場合も差異が生まれにくい
  • 設定ファイルを共有することでプロジェクトメンバー間で同じ環境を立ち上げられる
    インフラ環境のコードを定義したものをinfrastructure as codeと呼んだりする。
    設定ファイルをもとに環境を作ることができ、設定ファイルを見れば何がインストールされているのかもわかる。
  • PC環境を汚さずにすむ

npm ERR! ERESOLVE unable to resolve dependency treeの対処方法

npm ERR! ERESOLVE unable to resolve dependency treeの対処方法

SPAのブラウザバックのscroll復活をしたく、ためにしにreact-scroll-restorationを導入しようとしたらタイトルのエラーがでました。
react-scroll-restoration

結論

-save --legacy-peer-depsをnpm installのあとにつければいいそうです。

実際のエラー

$ npm install react-scroll-restoration
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: testApp@0.1.0
npm ERR! Found: react-router-dom@5.3.0
npm ERR! node_modules/react-router-dom
npm ERR!   react-router-dom@"^5.2.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react-router-dom@"^4.0.0" from react-scroll-restoration@1.0.8
npm ERR! node_modules/react-scroll-restoration
npm ERR!   react-scroll-restoration@"*" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /Users/userName/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/userName/.npm/_logs/2021-12-28T11_47_37_669Z-debug.log

npm ERR! Found: react-router-dom@5.3.0
↑因果関係があるライブラリの今使ってるバージョン
npm ERR! peer react-router-dom@"^4.0.0" from react-scroll-restoration@1.0.8
↑実際にさぽーとサポートしているバージョン

$ npm install react-scroll-restoration -save --legacy-peer-deps

npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@jest/types@27.0.6',
npm WARN EBADENGINE   required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.10.0', npm: '7.16.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: 'diff-sequences@27.0.6',
npm WARN EBADENGINE   required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.10.0', npm: '7.16.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: 'jest-diff@27.0.6',
npm WARN EBADENGINE   required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.10.0', npm: '7.16.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: 'jest-get-type@27.0.6',
npm WARN EBADENGINE   required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.10.0', npm: '7.16.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: 'pretty-format@27.0.6',
npm WARN EBADENGINE   required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.10.0', npm: '7.16.0' }
npm WARN EBADENGINE }

added 1 package, and audited 2569 packages in 13s

166 packages are looking for funding
  run `npm fund` for details

43 vulnerabilities (27 moderate, 13 high, 3 critical)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

無理やり入れているのでWARN出まくってますが、とりあえずinstallはできました。
余談ですが、インストールしようとしていたreact-scroll-restorationはうまく機能しませんでした。

PostgreSQL導入で躓いた

postgresを導入して起動したかったけどできなかった

備忘録として残してます。

macなのでbrewでインストール

$ brew install postgresql

文字コードUTF-8でデータベースの初期化

$ initdb /usr/local/var/postgres --encoding=UTF-8 --locale=ja_JP.UTF-8

The files belonging to this database system will be owned by user "username".
This user must also own the server process.

The database cluster will be initialized with locale "ja_JP.UTF-8".
initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8"
The default text search configuration will be set to "simple".

Data page checksums are disabled.

initdb: directory "/usr/local/var/postgres" exists but is not empty
If you want to create a new database system, either remove or empty
the directory "/usr/local/var/postgres" or run initdb
with an argument other than "/usr/local/var/postgres".

で、ここからDBの起動をしてエンコードを確認したかったのにこれ

$ postgres -D /usr/local/var/postgres
2021-12-28 08:55:23.530 JST [63749] FATAL:  lock file "postmaster.pid" already exists
2021-12-28 08:55:23.530 JST [63749] HINT:  Is another postmaster (PID 63717) running in data directory "/usr/local/var/postgres"?

Postgres が起動しなくなったら
ここを参照してみたものの治らず

$ psql 
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL:  database "username" does not exist

と思ったらデータベース作ってないので、最初は上記の文言が出るようです。

$ psql -l

エンコードも確認ができました。

FirebaseとReactでページネーション

はじめに

受注のあったアプリをFirebase+React+Typescriptで開発中です。
ページネーションと書きましたが、実際は次へと前へのボタン二つで実装です。
(※そして少々回りくどいかもしれません!!申し訳ありません!!)
Firebaseのクエリでは本物ページネーションが難しいため、開発中のアプリはAlgoliaを導入しました。
Firebase+Algoliaの開発記事はまた書こうと思います。

流れ

今回使うメインのデータの型

interface USER {
  uid: string
  name: string
  createdAt: Date
  image: string
}

今回用意するState
Stateの上が関連する説明として書いてます。

// fetchしたデータ、その時表示させる件数分しかsetしません
const  [ fetchData,  setFetchData ] = useState<USER[]>([]) // ①

// fetchDataで取得したデータの最初のtimestamp、ページを戻る場合に使う
// ちなみにtimestamp(createdAt)は、Firebaseだと下記のデータが入る
/*
createdAt: {
  nanoseconds: 34000000
  seconds: 1635892516
}
*/
const  [ firstTime,  setFirstTime ] = useState<Date>() // ②

// fetchDataで取得したデータの最後のtimestamp,ページを進む場合に使う
const  [ lastTime,  setLastTime ] = useState<Date>() // ③

// 全てのデータの最初のID
const  [ firstId, setFirstId ] = useState('') // ④

// 全てのデータの最後のID
const  [ lastId, setLastId ] = useState('') // ⑤

1.対象のデータをfetchして①のfirstTimeへsetする。
2.fetchしたデータの最初と最後のtimestamp(createdAt)をstateへset、最初の値を②のfirstTime、最後の値を③lastTimeへsetする。
3.fetchしたデータの最初と最後のID(uid)をstateへset、最初の値を④のfirstId、最後の値を⑤lastIdへsetする。
4.fetchしたデータに2でsetした最初と最後IDがあれば、ページを戻ったり進められないよう処理する。
※今回はフロント部分で矢印のボタンを制御するようにしました。
firstIdもlastIdも合致していない場合、どちらの矢印も表示させる f:id:zare926:20211129084607p:plain fetchDataの最初のデータのIDがfirstIdと合致している場合、戻る矢印は表示させない f:id:zare926:20211129084600p:plain fetchDataの最後のデータのIDがlastIdと合致している場合、進む矢印は表示させない f:id:zare926:20211129084631p:plain

tsxで書くとこんな感じ

{ fetchData[0].uid != firstId && 戻る矢印 }

{ fetchData[fetchData.length - 1].uid !=  lastId && 進む矢印 }

5.次に進む場合は、2でsetした③lastTimeの次のリストからデータをfetchする。
この時FirebaseのメソッドでstartAfterを使う。
6.前に戻る場合は、2でsetした②firstTimeの手前のリストからデータをfetchする。
この時fetchするデータをlimitで制限している場合、進むとは違って、limitToLastというメソッドとendBeforeを掛け合わせて使う。

という感じです。
下準備が多く、わかりにくく申し訳ありません…
これいらないんじゃないの?とか別の方法があれば教えてもらえたら幸いです!

コード

ざっくりとまとめるとこんな感じです。
今回fetchするデータはcollectionのusersを9件ずつ取得することにしてます。
フロント部分は最小限ですし、CSSも当たってないのでデザインしてください。

Pagination.tsx

import React, { useEffect, useState } from 'react'
import { db } from '../../../firebase' // ディレクトリ適当です、アプリごと変わります

interface USER {
  uid: string
  name: string
  createdAt: Date
  image: string
}

const Pagination = () => {
  const usersRef = db.collection('users')

  const [fetchData, setFetchData] = useState<USER[]>([])
  const [firstTime, setFirstTime] = useState<Date>()
  const [lastTime, setLastTime] = useState<Date>()
  const [firstId, setFirstId] = useState('')
  const [lastId, setLastId] = useState('')

  useEffect(() => {
    fetchUsersData()
  }, [])

  //  setStateをまとめてます
  const setMethod = (dataList: USER[]) => {
    setFirstTime(dataList[dataList.length - 1].createdAt)
    setLastTime(dataList[0].createdAt)
    setFirstId(dataList[dataList.length - 1].uid)
    setLastId(dataList[0].uid)
  }

  // 一番最初の9件を取りに行く
  const fetchUsersData = () => {
    let dataList: USER[] = []
    usersRef
      .limit(9)
      .orderBy('createdAt', 'desc')
      .get()
      .then((snapshot) => {
        snapshot.forEach((doc) => {
          const data = doc.data()
          const newData = {
            uid: data.uid,
            name: data.name,
            createdAt: data.createdAt,
            image: data.image,
          }
          dataList.push(newData)
        })
        setFetchData(dataList)
        setMethod(dataList)
      })
  }

  //  次のページ分を取りに行く
  // startAfterが指定したcreatedAt以降のデータを取ってきてくれる
  const fetchNextUsersData = () => {
    let dataList: USER[] = []
    usersRef
      .limit(9)
      .orderBy('createdAt', 'desc')
      .startAfter(lastTime)
      .get()
      .then((snapshot) => {
        snapshot.forEach((doc) => {
          const data = doc.data()
          const newData = {
            uid: data.uid,
            name: data.name,
            createdAt: data.createdAt,
            image: data.image,
          }
          dataList.push(newData)
        })
        setFetchData(dataList)
        setMethod(dataList)
      })
  }

  //  前のページ分を取りに行く
  // endBeforeとlimitToLastで指定したcreatedAtより手前のデータを取ってきてくれる
  const fetchPrevUsersData = () => {
    let dataList: USER[] = []
    usersRef
      .limitToLast(9)
      .orderBy('createdAt', 'desc')
      .endBefore(firstTime)
      .get()
      .then((snapshot) => {
        snapshot.forEach((doc) => {
          const data = doc.data()
          const newData = {
            uid: data.uid,
            name: data.name,
            createdAt: data.createdAt,
            image: data.image,
          }
          dataList.push(newData)
        })
        setFetchData(dataList)
        setMethod(dataList)
      })
  }
  return (
    <>
      {fetchData.map((fd: USER) => (
        <div>
          <img src={fd.image} />
        </div>
      ))}

      <div className='prevBtn'>
        {fetchData[0].uid != firstId && <img src={左矢印} onClick={() => fetchPrevUsersData()} />}
      </div>
      <div className='nextBtn'>
        {fetchData[fetchData.length - 1].uid != lastId && <img src={右矢印} onClick={() => fetchNextUsersData()} />}
      </div>
    </>
  )
}

export default Pagination


これでうまく機能すると思います!

【Rails】アクセス数をカウントしたかったので、impressionistを導入

初めに

ブログを作成していたので、記事にアクセスした回数を確認したく、探してみたところimpressionistというgemを発見。
少しつまづいたのと、まだ仮実装ですが、見返せるように投稿しておきます。

開発環境

バージョン
Ruby 2.5.1
Rails 5.2.3
impressionist 1.6.1

impressionistのバージョンはRails5なら1.6.1でないとエラーが出るようです。

やり方

ざっくりとですが、カラムを作ったり、モデルにコードを書いたりします。
カウントしたい対象のテーブルにimpressions_countというカラムをintegerで作ります。

下記はあくまで例です。

class CreateUsers < ActiveRecord::Migration[5.1]
  def change
    create_table :users do |t|
      t.string :name
      t.integer :impressions_count, default: 0
 
      t.timestamps
    end
  end
end

gemをインストールしましょう。
gem

gem 'impressionist'

$ bundle install してimpressionistをgenerateします。
ターミナル

$ rails g impressionist
Running via Spring preloader in process 134476
      invoke  active_record
      create    db/migrate/20180804231718_create_impressions_table.rb
      create  config/initializers/impression.rb

マイグレーションは下記が出来上がります。
migration.rb

class CreateImpressionsTable < ActiveRecord::Migration[5.1]
  def self.up
    create_table :impressions, :force => true do |t|
      t.string :impressionable_type
      t.integer :impressionable_id
      t.integer :user_id
      t.string :controller_name
      t.string :action_name
      t.string :view_name
      t.string :request_hash
      t.string :ip_address
      t.string :session_hash
      t.text :message
      t.text :referrer
      t.text :params
      t.timestamps
    end
    add_index :impressions, [:impressionable_type, :message, :impressionable_id], :name => "impressionable_type_message_index", :unique => false, :length => {:message => 255 }
    add_index :impressions, [:impressionable_type, :impressionable_id, :request_hash], :name => "poly_request_index", :unique => false
    add_index :impressions, [:impressionable_type, :impressionable_id, :ip_address], :name => "poly_ip_index", :unique => false
    add_index :impressions, [:impressionable_type, :impressionable_id, :session_hash], :name => "poly_session_index", :unique => false
    add_index :impressions, [:controller_name,:action_name,:request_hash], :name => "controlleraction_request_index", :unique => false
    add_index :impressions, [:controller_name,:action_name,:ip_address], :name => "controlleraction_ip_index", :unique => false
    add_index :impressions, [:controller_name,:action_name,:session_hash], :name => "controlleraction_session_index", :unique => false
    add_index :impressions, [:impressionable_type, :impressionable_id, :params], :name => "poly_params_request_index", :unique => false, :length => {:params => 255 }
    add_index :impressions, :user_id
  end
 
  def self.down
    drop_table :impressions
  end
end

migrationしましょう。
ターミナル

$ rails db:migrate

モデルに:counter_cacheを設定

class User < ApplicationRecord
    is_impressionable counter_cache: true
end

コントローラーに以下設定

  def show
    @user = User.find(params[:id])
    impressionist(@user, nil, :unique => [:session_hash])
  end

今回はuserとしてますが、記事とかであればarticleでもいいですし、動画ならvideoとかですかね?
また、:unique => [:session_hash]は自分の場合一旦消しました。
おそらくこれが無いと、同一のユーザーがアクセスした分カウントされてしまうのだと思われます。
ですが、TypeError - can't quote Rack::Session::SessionIdといったエラーが出てしまい、一旦カウントができる状態で仮完了としました。
エラーの参考記事はこちらです。

ruby on rails - TypeError - can't quote Rack::Session::SessionId - Stack Overflow
あとはViewで呼び出せばOKです。

<%= @user.impressions_count %>

このあとランキングを作ろうと思ってます。

参考

https://remonote.jp/rails-impressionist-ranking

https://github.com/charlotte-ruby/impressionist