20190302のdockerに関する記事は11件です。

Dockerコマンド チュートリアル

Dockerの基本的な操作方法を記載しておく。GUIツールを利用してみたが、やはりCLIのほうがうまく動作するためCLIでの操作を推奨する。Dockerを扱う上での必須理解項目は「イメージ」、「コンテナ」である。

1.基本的な操作

イメージの検索

DockerHubからイメージをキーワード検索する。

  $ docker search centos
  NAME                           DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
  centos                         The official build of CentOS.                   3500      [OK]       
  jdeathe/centos-ssh             CentOS-6 6.9 x86_64 / CentOS-7 7.3.1611 x8...   77                   [OK]

イメージの取得

イメージ名:タグ名を指定して取得する。タグ名を明記しない場合は「latest」が付与される。

  $ docker pull centos:latest
  latest: Pulling from library/centos
  d5e46245fe40: Pull complete 
  Digest:sha256:aebf12af704307dfa0079b3babdca8d7e8ff6564696882bcb5d11f1d461f9ee9
  Status: Downloaded newer image for centos:latest

PC上に保存されているイメージを表示

  $ docker images
  REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
  centos                        latest              3bee3060bfc8        12 days ago         193 MB

PC上に保存されているイメージを削除

  $ docker rmi 3bee3060bfc8
  Untagged: centos:latest
  Untagged: centos@sha256:aebf12af704307dfa0079b3babdca8d7e8ff6564696882bcb5d11f1d461f9ee9
  Deleted: sha256:3bee3060bfc81c061ce7069df35ce090593bda584d4ef464bc0f38086c11371d
  Deleted: sha256:dc1e2dcdc7b6ff86d785fa16cf97464d263d04346a191c57b5ca8a66b4155861

イメージの起動

方法1はexitするとコンテナが終了してしまう。方法2はexitしてもコンテナが終了しない方法である。ただし、方法1の場合でも「Ctrl+p,Ctrl+q」によりコンテナから脱出かつコンテナは終了しない。

方法1

  $ docker run -it centos:latest /bin/bash
  [root@2fe147e75dc9 /]# uname -a
  Linux 2fe147e75dc9 4.9.27-moby #1 SMP Thu May 11 04:01:18 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
  [root@2fe147e75dc9 /]# cat /etc/redhat-release 
  CentOS Linux release 7.3.1611 (Core)

方法2

  $ docker run -itd centos:latest
  4a82a4ec72bf1b28b2abe84da1b4995c23cf4aa74f32364bb3e81d75db14dd45

起動しているコンテナを確認する

  $ docker ps
  CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
  5c304f72c6d6        centos:latest       "/bin/bash"         3 minutes ago       Up 3 minutes               

起動しているコンテナを停止させる

  $ docker stop 5c304f72c6d6
  5c304f72c6d6

起動しているコンテナを再起動させる

  $ docker ps
  CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
  048697b53b77        centos:latest       "/bin/bash"         19 seconds ago      Up 16 seconds                           lucid_franklin

  $ docker restart 048697b53b77
  048697b53b77

  $ docker ps
  CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
  048697b53b77        centos:latest       "/bin/bash"         About a minute ago   Up 9 seconds                            lucid_franklin

コンテナに接続する

5で紹介したイメージがコンテナの場合バージョン。
方法1はexitするとコンテナが終了してしまうため、「Ctrl+p,Ctrl+q」すること。方法2はexitしても終了しない。

方法1

  $ docker attach 048697b53b77

方法2

  $ docker exec -it 82f647b208ea /bin/bash
  [root@82f647b208ea /]# exit
  exit

  $ docker ps
  CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
  82f647b208ea        centos:latest       "/bin/bash"         30 seconds ago      Up 28 seconds                           nifty_wright

2.少し高度な操作

ポートのマッピング

基本

  $ docker run -d -p 8080:80 <image_name> -it /bin/bash

IPアドレスも指定

  $ docker run -d -p 192.168.0.219:8080:80 <image_name>

ボリュームのマッピング

  $ docker run -d -v /tmp/:/mnt/ <image_name>

コンテナのイメージ化

  $ docker commit <Container ID> <image_name>:<tag>

実用的なイメージの起動方法

  $ docker run -it -p 8000:8000 -v /tmp/006_log/01_arena/:/var/log/cowrie/ splunk:latest

イメージのエクスポート

  $ docker save <image_name>:<tag_name> > <filename>
  $ docker save --output <filename> <image_name>:<tag_name>
  $ docker save -o <filename> <image_name>:<tag_name>

イメージのインポート

  $ docker load < <filename>
  $ docker load --input <file_name>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メモリ512MBで動く軽量Kubernetes!k3sをDocker上で試してみた→失敗

記事を書いたきっかけ

Publickeyの記事を読んで気になったので、動かしてみたくなって、実際に動かしてみた。
「k3sとは何か?」に関しては、記事を読んでもらうのが良いと思う。

Kubernetesをわずか40MBのシングルバイナリとして軽量かつシンプルにした新ディストリビューション「k3s」登場。Rancher Labsがオープンソースで公開 - Publickey

とりあえずはk3sが動く環境を整えてみるが目標。

...が、手元のPCの環境を汚したくなくて、Dockerの中でk3sを動かそうとしたところ、執筆時点では失敗...
素直に、クリーンな物理マシンかVMでやれば動かせるかも?
どなたかトライして成功したらコメント下さい...

概要

  • k3sの公式リポジトリ rancher/k3s (2019/03/02時点)の手順を参考に実践。
  • ただし、手元のPCに本家Kubernetesがインストール済みで、環境を汚したくなかったので、Dockerのコンテナの中で動かす方法をお試し。

マシン環境(ホストマシン)

# OS
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS"

# Docker
$ docker version
Client:
 Version:           18.09.3
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        774a1f4
 Built:             Thu Feb 28 06:53:11 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.3
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       774a1f4
  Built:            Thu Feb 28 05:59:55 2019
  OS/Arch:          linux/amd64
  Experimental:     false

動かしてみる

まずは公式リポジトリのソースをチェックアウトから...と思ったけど、このリポジトリ、けっこう重い...

なので、今回やりたい手順(Running in Docker (and docker-compose)で必要そうなdocker-compose.ymlだけダウンロードした。

curl -L "https://raw.githubusercontent.com/rancher/k3s/master/docker-compose.yml" -o docker-compose.yml

公式手順の通り、クラスタを立ち上げ。

$ docker-compose up --scale node=3
...()...

# 結構なメッセージ量に紛れてエラーっぽいメッセージがチラホラ...んー?

クラスタの状態を確認。

$ kubectl --kubeconfig kubeconfig.yaml get node
NAME           STATUS   ROLES    AGE    VERSION
164b688fd280   Ready    <none>   118s   v1.13.3-k3s.6
3a7ad8d03bed   Ready    <none>   119s   v1.13.3-k3s.6
5b48d23be7ea   Ready    <none>   118s   v1.13.3-k3s.6

動いていそう...?
だけどPodが全然動いて無い...

$ kubectl --kubeconfig kubeconfig.yaml get pods --all-namespaces
NAMESPACE     NAME                         READY   STATUS             RESTARTS   AGE
kube-system   coredns-7748f7f6df-ps6jb     1/1     Running            0          3m50s
kube-system   helm-install-traefik-lzkgw   0/1     CrashLoopBackOff   4          3m50s

失敗だ...これ...

さらなる失敗談(恥の上塗りとも言う)

k3sの公式リポジトリの教え(Running in Docker (and docker-compose)に従う前に、「シングルバイナリで簡単にインストールできるなら、ubuntu:18.04のイメージ使っていけるはず!」と思って、試した時の話。

そもそも、コンテナでの起動オプションとか調べずに突っ走ったことが原因な気もするけど、あれ〜?ってなった。

インストール

まずはubuntu:18.04のイメージを起動し、空の環境を用意する。

$ docker run -it ubuntu:18.04
root@6e9a76a9bbe3:/#

curlコマンドを使って、k3sをダウンロードする。

# curlコマンドが無いので、先にインストール
# (iproute2は後で使う)
root@6e9a76a9bbe3:/# apt-get update && apt-get install -y curl iproute2
...()...

# k3sをGitHubからダウンロード
root@6e9a76a9bbe3:/# curl -L "https://github.com/rancher/k3s/releases/download/v0.1.0/k3s" -o /usr/local/bin/k3s
...()...

# 実行権限を付与
root@6e9a76a9bbe3:/# chmod +x /usr/local/bin/k3s

# 確認
root@6e9a76a9bbe3:/# k3s --help
NAME:
   k3s - Kubernetes, but small and simple

USAGE:
   k3s [global options] command [command options] [arguments...]

VERSION:
   dev (HEAD)

COMMANDS:
     server   Run management server
     agent    Run node agent
     kubectl  Run kubectl
     crictl   Run crictl
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug        Turn on debug logs
   --help, -h     show help
   --version, -v  print the version

動いていそう。

せっかくなので、Master-Node構成を取るべく、同じ要領でもう1つコンテナを立ち上げ、k3sをインストールしておく。

クラスタ立ち上げ

k3s公式リポジトリのQuick Startの内容をそのままを実行してみる。
コンテナの中では、sudoが要らないので、そこだけ注意。

# 以下は失敗(後述)
root@6e9a76a9bbe3:/# k3s server &
[1] 2775
root@6e9a76a9bbe3:/# INFO[0000] Preparing data dir /var/lib/rancher/k3s/data/4df430e1473d0225734948e562863c82f20d658ed9c420c77e168aec42eccdb5 
INFO[2019-03-02T12:18:36.307868926Z] Starting k3s v0.1.0 (91251aa)                
...()...

[1]+  Exit 255                k3s server

kubeadm initと似た感じでメッセージ出力された...と思ったけど、止まってるー!?

k3sの公式リポジトリに置いてあるdocker-compose.ymlを覗いてみると、

version: '3'
services:
  server:
    image: rancher/k3s:v0.1.0
    command: server --disable-agent
    # ...(略)...

おっと何やら--disable-agentというオプションが必要そう。

root@6e9a76a9bbe3:/# k3s server --disable-agent &
[1] 2821
root@6e9a76a9bbe3:/# INFO[2019-03-02T12:21:49.330150358Z] Starting k3s v0.1.0 (91251aa)                
...()...
INFO[2019-03-02T12:21:49.815062892Z] k3s is up and running

今度は動いてそう...?

root@6e9a76a9bbe3:/# k3s kubectl get node
No resources found.

んー?
まぁ、一旦無視してNodeを追加してみる。

Node追加のコマンドのフォーマットは下記の通り。

k3s agent --server https://<Master IP>:6443 --token <Token>

<Master IP>はiproute2パッケージで入れたipコマンドで確認。

root@6e9a76a9bbe3:/# ip address show eth0
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

<Token>/var/lib/rancher/k3s/server/node-tokenに格納されているそう。

root@6e9a76a9bbe3:/# cat /var/lib/rancher/k3s/server/node-token
K10bf48c01ba01fe012bcb74ada31b6baabb0a82269af8a2d68c9160a1faf95a68a::node:1902f272fd82f0798cf7a99e0ee64e18

長いけど、全部かな?
Node用に立ち上げたもう一方のコンテナで、Node追加コマンドを実行。

# これも失敗(後述)
root@b303f31b9a67:/# k3s agent --server https://172.17.0.2:6443 --token K10bf48c01ba01fe012bcb74ada31b6baabb0a82269af8a2d68c9160a1faf95a68a::node:1902f272fd82f0798cf7a99e0ee64e18
INFO[0000] Preparing data dir /var/lib/rancher/k3s/data/4df430e1473d0225734948e562863c82f20d658ed9c420c77e168aec42eccdb5 
INFO[2019-03-02T12:41:02.093092358Z] Starting k3s agent v0.1.0 (91251aa)          
INFO[2019-03-02T12:41:02.590974830Z] Logging containerd to /var/lib/rancher/k3s/agent/containerd/containerd.log 
INFO[2019-03-02T12:41:02.591223430Z] Running containerd -c /var/lib/rancher/k3s/agent/etc/containerd/config.toml -a /run/k3s/containerd/containerd.sock --state /run/k3s/containerd --root /var/lib/rancher/k3s/agent/containerd 
INFO[2019-03-02T12:41:02.591501029Z] Waiting for containerd startup: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial unix /run/k3s/containerd/containerd.sock: connect: no such file or directory" 
WARN[2019-03-02T12:41:03.595279617Z] failed to write value 1 at /proc/sys/net/bridge/bridge-nf-call-iptables: open /proc/sys/net/bridge/bridge-nf-call-iptables: no such file or directory 
WARN[2019-03-02T12:41:03.595424541Z] failed to write value 1 at /proc/sys/net/ipv4/ip_forward: open /proc/sys/net/ipv4/ip_forward: read-only file system 
INFO[2019-03-02T12:41:03.600671376Z] Connecting to wss://172.17.0.2:6443/v1-k3s/connect 
INFO[2019-03-02T12:41:03.600777136Z] Connecting to proxy                           url="wss://172.17.0.2:6443/v1-k3s/connect"
WARN[2019-03-02T12:41:03.610703830Z] Disabling CPU quotas due to missing cpu.cfs_period_us 
INFO[2019-03-02T12:41:03.610955979Z] Running kubelet --healthz-bind-address 127.0.0.1 --read-only-port 0 --allow-privileged=true --cluster-domain cluster.local --kubeconfig /var/lib/rancher/k3s/agent/kubeconfig.yaml --eviction-hard imagefs.available<5%,nodefs.available<5% --eviction-minimum-reclaim imagefs.available=10%,nodefs.available=10% --fail-swap-on=false --cgroup-driver cgroupfs --root-dir /var/lib/rancher/k3s/agent/kubelet --cert-dir /var/lib/rancher/k3s/agent/kubelet/pki --seccomp-profile-root /var/lib/rancher/k3s/agent/kubelet/seccomp --cni-conf-dir /var/lib/rancher/k3s/agent/etc/cni/net.d --cni-bin-dir /var/lib/rancher/k3s/data/4df430e1473d0225734948e562863c82f20d658ed9c420c77e168aec42eccdb5/bin --cluster-dns 10.43.0.10 --container-runtime remote --container-runtime-endpoint unix:///run/k3s/containerd/containerd.sock --address 127.0.0.1 --anonymous-auth=false --client-ca-file /var/lib/rancher/k3s/agent/client-ca.pem --hostname-override b303f31b9a67 --cpu-cfs-quota=false 
Flag --allow-privileged has been deprecated, will be removed in a future version
W0302 12:41:03.611511    2828 server.go:194] WARNING: all flags other than --config, --write-config-to, and --cleanup are deprecated. Please begin using a config file ASAP.
INFO[2019-03-02T12:41:03.625252893Z] waiting for node b303f31b9a67: nodes "b303f31b9a67" not found 
W0302 12:41:03.626363    2828 proxier.go:480] Failed to read file /lib/modules/4.15.0-45-generic/modules.builtin with error open /lib/modules/4.15.0-45-generic/modules.builtin: no such file or directory. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.629437    2828 proxier.go:493] Failed to load kernel module ip_vs with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.633111    2828 proxier.go:493] Failed to load kernel module ip_vs_rr with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.637358    2828 proxier.go:493] Failed to load kernel module ip_vs_wrr with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.637778    2828 proxier.go:493] Failed to load kernel module ip_vs_sh with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.638181    2828 proxier.go:493] Failed to load kernel module nf_conntrack_ipv4 with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.642478    2828 node.go:103] Failed to retrieve node info: nodes "b303f31b9a67" not found
I0302 12:41:03.642508    2828 server_others.go:148] Using iptables Proxier.
F0302 12:41:03.642619    2828 server.go:377] unable to create proxier: can't set sysctl net/ipv4/conf/all/route_localnet: open /proc/sys/net/ipv4/conf/all/route_localnet: read-only file system

同じくk3sの公式リポジトリのdocker-compose.ymlを覗いてみると、

version: '3'
services:
  # ...(略)...
  node:
    image: rancher/k3s:v0.1.0
    tmpfs:
    - /run
    - /var/run
    privileged: true
    # ...(略)...

tmpfsprivilegedが必要そう。
Node用のコンテナは作り直し...

$ docker run -it --mount type=tmpfs,destination=/run --mount type=tmpfs,destination=/var/run --privileged ubuntu:18.04 
root@f0b7efd14ae8:/# apt-get update && apt-get install -y curl iproute2
...()...
root@f0b7efd14ae8:/# curl -L "https://github.com/rancher/k3s/releases/download/v0.1.0/k3s" -o /usr/local/bin/k3s
...()...
root@f0b7efd14ae8:/# chmod +x /usr/local/bin/k3s

気を取り直して、もう一度Node追加をトライ。

# これも失敗
root@f0b7efd14ae8:/# k3s agent --server https://172.17.0.2:6443 --token K10bf48c01ba01fe012bcb74ada31b6baabb0a82269af8a2d68c9160a1faf95a68a::node:1902f272fd82f0798cf7a99e0ee64e18
...()...

...(以下が繰り返し出力)...
E0302 12:55:40.162851    2808 kuberuntime_manager.go:677] createPodSandbox for pod "coredns-7748f7f6df-rk9g5_kube-system(ca04369a-3ce5-11e9-9c1c-0242ac110002)" failed: rpc error: code = Unknown desc = failed to start sandbox container: failed to create containerd task: failed to mount rootfs component &{overlay overlay [workdir=/var/lib/rancher/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/18/work upperdir=/var/lib/rancher/k3s/agent/containerd/io.containerd.snapshotter.v1.overl

ここで断念。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メモリ512MBで動く軽量Kubernetes!k3sをDocker上で試してみた

記事を書いたきっかけ

Publickeyの記事を読んで気になったので、動かしてみたくなって、実際に動かしてみた。
「k3sとは何か?」に関しては、記事を読んでもらうのが良いと思う。

Kubernetesをわずか40MBのシングルバイナリとして軽量かつシンプルにした新ディストリビューション「k3s」登場。Rancher Labsがオープンソースで公開 - Publickey

とりあえずはk3sが動く環境を整えてみるが目標。

概要

  • k3sの公式リポジトリ rancher/k3s (2019/03/02時点)の手順を参考に実践。
  • ただし、手元のPCに本家Kubernetesがインストール済みで、環境を汚したくなかったので、Dockerのコンテナの中で動かす方法をお試し。

マシン環境(ホストマシン)

# OS
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS"

# Docker
$ docker version
Client:
 Version:           18.09.3
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        774a1f4
 Built:             Thu Feb 28 06:53:11 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.3
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       774a1f4
  Built:            Thu Feb 28 05:59:55 2019
  OS/Arch:          linux/amd64
  Experimental:     false

動かしてみる

まずは公式リポジトリのソースをチェックアウトから...と思ったけど、このリポジトリ、けっこう重い...

なので、今回やりたい手順(Running in Docker (and docker-compose)で必要そうなdocker-compose.ymlだけダウンロードした。

curl -L "https://raw.githubusercontent.com/rancher/k3s/master/docker-compose.yml" -o docker-compose.yml

公式手順の通り、クラスタを立ち上げ。

$ docker-compose up --scale node=3
...()...

# 結構なメッセージ量に紛れてエラーっぽいメッセージがチラホラ...んー?

クラスタの状態を確認。

$ kubectl --kubeconfig kubeconfig.yaml get node
NAME           STATUS   ROLES    AGE    VERSION
164b688fd280   Ready    <none>   118s   v1.13.3-k3s.6
3a7ad8d03bed   Ready    <none>   119s   v1.13.3-k3s.6
5b48d23be7ea   Ready    <none>   118s   v1.13.3-k3s.6

動いていそう...?
だけどPodが全然動いて無い...

$ kubectl --kubeconfig kubeconfig.yaml get pods --all-namespaces
NAMESPACE     NAME                         READY   STATUS             RESTARTS   AGE
kube-system   coredns-7748f7f6df-ps6jb     1/1     Running            0          3m50s
kube-system   helm-install-traefik-lzkgw   0/1     CrashLoopBackOff   4          3m50s

失敗だ...これ...

ログの内容を見ると、コンテナ内からカーネルモジュールが読み込めてない〜というようなエラーだったので、docker-compose.ymlにオプションを追加。

version: '3'
services:
  server:
    # ...(略)...

  node:
    # ...(略)...
    volumes:
    - /lib/modules:/lib/modules
    cap_add:
    - ALL

volumes:
  k3s-server: {}

これでトライしてみる。

$ docker-compose up --scale node=3
...()...

# 相変わらずエラーっぽいメッセージがチラホラ...んー?

ただクラスタの状態的には動いてそう。

$ kubectl --kubeconfig kubeconfig.yaml get pods --all-namespaces
NAMESPACE     NAME                         READY   STATUS    RESTARTS   AGE
kube-system   coredns-7748f7f6df-rvz5z     1/1     Running   0          3m19s
kube-system   helm-install-traefik-nmr75   1/1     Running   0          3m18s

$ kubectl --kubeconfig kubeconfig.yaml get nodes
NAME           STATUS     ROLES    AGE     VERSION
1a9985426a91   Ready      <none>   71s     v1.13.3-k3s.6
5a3963d09b0c   Ready      <none>   70s     v1.13.3-k3s.6
6ec3ef89103f   Ready      <none>   69s     v1.13.3-k3s.6

とりあえずは動いてそう。

ちなみに...本家Kubernetesだと、get nodesの結果でMasterも表示されますが、今回は表示されませんね。そういう仕様なのでしょうか...?

# コンテナはMasterを含めて4つ起動
$ docker-compose ps
    Name                  Command               State           Ports         
------------------------------------------------------------------------------
k3s_node_1     /bin/k3s agent                   Up                            
k3s_node_2     /bin/k3s agent                   Up                            
k3s_node_3     /bin/k3s agent                   Up                            
k3s_server_1   /bin/k3s server --disable- ...   Up      0.0.0.0:6443->6443/tcp

念ため動作確認

確認のため、下記のマニフェストを使って、Podを1つ動かしてみる。

apiVersion: v1
kind: Pod
metadata:
  name: sample-pod
spec:
  containers:
    - name: nginx-container
      image: nginx
      ports:
      - containerPort: 80

カレントにkubeconfig.yamlが吐かれるので、それを使う。

$ kubectl --kubeconfig kubeconfig.yaml apply -f sample-pod.yaml 
pod/sample-pod created

$ kubectl --kubeconfig kubeconfig.yaml get pods
NAME         READY   STATUS    RESTARTS   AGE
sample-pod   1/1     Running   0          100s

動いてそう!
...まぁ、ロクに機能を動かしていないので、実際は不具合が起こりそうですが、とりあえずお試できる環境は手に入りました。

失敗談

k3sの公式リポジトリの教え(Running in Docker (and docker-compose)に従う前に、「シングルバイナリで簡単にインストールできるなら、ubuntu:18.04のイメージ使っていけるはず!」と思って、試した時の話。

そもそも、コンテナでの起動オプションとか調べずに突っ走ったことが原因な気もするけど、あれ〜?ってなった。
どなたかトライして成功したらコメント下さい。

インストール

まずはubuntu:18.04のイメージを起動し、空の環境を用意する。

$ docker run -it ubuntu:18.04
root@6e9a76a9bbe3:/#

curlコマンドを使って、k3sをダウンロードする。

# curlコマンドが無いので、先にインストール
# (iproute2は後で使う)
root@6e9a76a9bbe3:/# apt-get update && apt-get install -y curl iproute2
...()...

# k3sをGitHubからダウンロード
root@6e9a76a9bbe3:/# curl -L "https://github.com/rancher/k3s/releases/download/v0.1.0/k3s" -o /usr/local/bin/k3s
...()...

# 実行権限を付与
root@6e9a76a9bbe3:/# chmod +x /usr/local/bin/k3s

# 確認
root@6e9a76a9bbe3:/# k3s --help
NAME:
   k3s - Kubernetes, but small and simple

USAGE:
   k3s [global options] command [command options] [arguments...]

VERSION:
   dev (HEAD)

COMMANDS:
     server   Run management server
     agent    Run node agent
     kubectl  Run kubectl
     crictl   Run crictl
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug        Turn on debug logs
   --help, -h     show help
   --version, -v  print the version

動いていそう。

せっかくなので、Master-Node構成を取るべく、同じ要領でもう1つコンテナを立ち上げ、k3sをインストールしておく。

クラスタ立ち上げ

k3s公式リポジトリのQuick Startの内容をそのままを実行してみる。
コンテナの中では、sudoが要らないので、そこだけ注意。

# 以下は失敗(後述)
root@6e9a76a9bbe3:/# k3s server &
[1] 2775
root@6e9a76a9bbe3:/# INFO[0000] Preparing data dir /var/lib/rancher/k3s/data/4df430e1473d0225734948e562863c82f20d658ed9c420c77e168aec42eccdb5 
INFO[2019-03-02T12:18:36.307868926Z] Starting k3s v0.1.0 (91251aa)                
...()...

[1]+  Exit 255                k3s server

kubeadm initと似た感じでメッセージ出力された...と思ったけど、止まってるー!?

k3sの公式リポジトリに置いてあるdocker-compose.ymlを覗いてみると、

version: '3'
services:
  server:
    image: rancher/k3s:v0.1.0
    command: server --disable-agent
    # ...(略)...

おっと何やら--disable-agentというオプションが必要そう。

root@6e9a76a9bbe3:/# k3s server --disable-agent &
[1] 2821
root@6e9a76a9bbe3:/# INFO[2019-03-02T12:21:49.330150358Z] Starting k3s v0.1.0 (91251aa)                
...()...
INFO[2019-03-02T12:21:49.815062892Z] k3s is up and running

今度は動いてそう...?

root@6e9a76a9bbe3:/# k3s kubectl get node
No resources found.

んー?
まぁ、一旦無視してNodeを追加してみる。

Node追加のコマンドのフォーマットは下記の通り。

k3s agent --server https://<Master IP>:6443 --token <Token>

<Master IP>はiproute2パッケージで入れたipコマンドで確認。

root@6e9a76a9bbe3:/# ip address show eth0
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

<Token>/var/lib/rancher/k3s/server/node-tokenに格納されているそう。

root@6e9a76a9bbe3:/# cat /var/lib/rancher/k3s/server/node-token
K10bf48c01ba01fe012bcb74ada31b6baabb0a82269af8a2d68c9160a1faf95a68a::node:1902f272fd82f0798cf7a99e0ee64e18

長いけど、全部かな?
Node用に立ち上げたもう一方のコンテナで、Node追加コマンドを実行。

# これも失敗(後述)
root@b303f31b9a67:/# k3s agent --server https://172.17.0.2:6443 --token K10bf48c01ba01fe012bcb74ada31b6baabb0a82269af8a2d68c9160a1faf95a68a::node:1902f272fd82f0798cf7a99e0ee64e18
INFO[0000] Preparing data dir /var/lib/rancher/k3s/data/4df430e1473d0225734948e562863c82f20d658ed9c420c77e168aec42eccdb5 
INFO[2019-03-02T12:41:02.093092358Z] Starting k3s agent v0.1.0 (91251aa)          
INFO[2019-03-02T12:41:02.590974830Z] Logging containerd to /var/lib/rancher/k3s/agent/containerd/containerd.log 
INFO[2019-03-02T12:41:02.591223430Z] Running containerd -c /var/lib/rancher/k3s/agent/etc/containerd/config.toml -a /run/k3s/containerd/containerd.sock --state /run/k3s/containerd --root /var/lib/rancher/k3s/agent/containerd 
INFO[2019-03-02T12:41:02.591501029Z] Waiting for containerd startup: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial unix /run/k3s/containerd/containerd.sock: connect: no such file or directory" 
WARN[2019-03-02T12:41:03.595279617Z] failed to write value 1 at /proc/sys/net/bridge/bridge-nf-call-iptables: open /proc/sys/net/bridge/bridge-nf-call-iptables: no such file or directory 
WARN[2019-03-02T12:41:03.595424541Z] failed to write value 1 at /proc/sys/net/ipv4/ip_forward: open /proc/sys/net/ipv4/ip_forward: read-only file system 
INFO[2019-03-02T12:41:03.600671376Z] Connecting to wss://172.17.0.2:6443/v1-k3s/connect 
INFO[2019-03-02T12:41:03.600777136Z] Connecting to proxy                           url="wss://172.17.0.2:6443/v1-k3s/connect"
WARN[2019-03-02T12:41:03.610703830Z] Disabling CPU quotas due to missing cpu.cfs_period_us 
INFO[2019-03-02T12:41:03.610955979Z] Running kubelet --healthz-bind-address 127.0.0.1 --read-only-port 0 --allow-privileged=true --cluster-domain cluster.local --kubeconfig /var/lib/rancher/k3s/agent/kubeconfig.yaml --eviction-hard imagefs.available<5%,nodefs.available<5% --eviction-minimum-reclaim imagefs.available=10%,nodefs.available=10% --fail-swap-on=false --cgroup-driver cgroupfs --root-dir /var/lib/rancher/k3s/agent/kubelet --cert-dir /var/lib/rancher/k3s/agent/kubelet/pki --seccomp-profile-root /var/lib/rancher/k3s/agent/kubelet/seccomp --cni-conf-dir /var/lib/rancher/k3s/agent/etc/cni/net.d --cni-bin-dir /var/lib/rancher/k3s/data/4df430e1473d0225734948e562863c82f20d658ed9c420c77e168aec42eccdb5/bin --cluster-dns 10.43.0.10 --container-runtime remote --container-runtime-endpoint unix:///run/k3s/containerd/containerd.sock --address 127.0.0.1 --anonymous-auth=false --client-ca-file /var/lib/rancher/k3s/agent/client-ca.pem --hostname-override b303f31b9a67 --cpu-cfs-quota=false 
Flag --allow-privileged has been deprecated, will be removed in a future version
W0302 12:41:03.611511    2828 server.go:194] WARNING: all flags other than --config, --write-config-to, and --cleanup are deprecated. Please begin using a config file ASAP.
INFO[2019-03-02T12:41:03.625252893Z] waiting for node b303f31b9a67: nodes "b303f31b9a67" not found 
W0302 12:41:03.626363    2828 proxier.go:480] Failed to read file /lib/modules/4.15.0-45-generic/modules.builtin with error open /lib/modules/4.15.0-45-generic/modules.builtin: no such file or directory. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.629437    2828 proxier.go:493] Failed to load kernel module ip_vs with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.633111    2828 proxier.go:493] Failed to load kernel module ip_vs_rr with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.637358    2828 proxier.go:493] Failed to load kernel module ip_vs_wrr with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.637778    2828 proxier.go:493] Failed to load kernel module ip_vs_sh with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.638181    2828 proxier.go:493] Failed to load kernel module nf_conntrack_ipv4 with modprobe. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules
W0302 12:41:03.642478    2828 node.go:103] Failed to retrieve node info: nodes "b303f31b9a67" not found
I0302 12:41:03.642508    2828 server_others.go:148] Using iptables Proxier.
F0302 12:41:03.642619    2828 server.go:377] unable to create proxier: can't set sysctl net/ipv4/conf/all/route_localnet: open /proc/sys/net/ipv4/conf/all/route_localnet: read-only file system

同じくk3sの公式リポジトリのdocker-compose.ymlを覗いてみると、

version: '3'
services:
  # ...(略)...
  node:
    image: rancher/k3s:v0.1.0
    tmpfs:
    - /run
    - /var/run
    privileged: true
    # ...(略)...

tmpfsprivilegedが必要そう。
Node用のコンテナは作り直し...

$ docker run -it --mount type=tmpfs,destination=/run --mount type=tmpfs,destination=/var/run --privileged ubuntu:18.04 
root@f0b7efd14ae8:/# apt-get update && apt-get install -y curl iproute2
...()...
root@f0b7efd14ae8:/# curl -L "https://github.com/rancher/k3s/releases/download/v0.1.0/k3s" -o /usr/local/bin/k3s
...()...
root@f0b7efd14ae8:/# chmod +x /usr/local/bin/k3s

気を取り直して、もう一度Node追加をトライ。

# これも失敗
root@f0b7efd14ae8:/# k3s agent --server https://172.17.0.2:6443 --token K10bf48c01ba01fe012bcb74ada31b6baabb0a82269af8a2d68c9160a1faf95a68a::node:1902f272fd82f0798cf7a99e0ee64e18
...()...

...(以下が繰り返し出力)...
E0302 12:55:40.162851    2808 kuberuntime_manager.go:677] createPodSandbox for pod "coredns-7748f7f6df-rk9g5_kube-system(ca04369a-3ce5-11e9-9c1c-0242ac110002)" failed: rpc error: code = Unknown desc = failed to start sandbox container: failed to create containerd task: failed to mount rootfs component &{overlay overlay [workdir=/var/lib/rancher/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/18/work upperdir=/var/lib/rancher/k3s/agent/containerd/io.containerd.snapshotter.v1.overl

ここで断念。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-compose で PHP7.2 + Apache + MySQL + phpMyAdmin 環境を構築

Docker の学習メモです。

本記事でのコンテナ作成は全て Docker Hub の image を使用して行なっています。
Dockerfile からのイメージ作成はまた今度。

ディレクトリ構造

  .
  ├── docker-compose.yml
  └── html
  │    └── index.php
  └── php.ini

docker-compose.yml

docker-compose.yml
version: '3'

services:
  php:
    image: php:7.2-apache
    volumes:
      - ./php.ini:/usr/local/etc/php/php.ini
      - ./html:/var/www/html
    ports:
      - 8080:80
  mysql:
    image: mysql:5.7
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=test
      - MYSQL_USER=test
      - MYSQL_PASSWORD=test
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=mysql
      - PMA_USER=test
      - PMA_PASSWORD=test
    links:
      - mysql
    ports:
      - 4040:80
    volumes:
      - ./phpmyadmin/sessions:/sessions

index.php

html/index.php
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>php7.2-apache</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<?php phpinfo(); ?>
</body>
</html>

php.ini

php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

現在のコンテナ稼働状況を確認

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

稼働中のコンテナが存在していないため、何も表示されない。

コンテナの作成と開始

$ docker-compose up -d
Creating network "php72-apache_default" with the default driver
Creating php72-apache_mysql_1 ... done
Creating php72-apache_php_1        ... done
Creating php72-apache_phpmyadmin_1 ... done

コンテナの稼働状況を確認する。

$ docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED              STATUS              PORTS                            NAMES
120e4b86b987        phpmyadmin/phpmyadmin   "/run.sh supervisord…"   About a minute ago   Up About a minute   9000/tcp, 0.0.0.0:4040->80/tcp   php72-apache_phpmyadmin_1
bf42cd71d3d4        php:7.2-apache          "docker-php-entrypoi…"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp             php72-apache_php_1
699f32a6424e        mysql:5.7               "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp, 33060/tcp              php72-apache_mysql_1

PHP の確認

http://localhost:8080/

ローカルの html/index.php の内容を変更すると反映される。

MySQL + phpMyAdmin の確認

http://localhost:4040/

サービスの停止

docker-compose.yml に記載されているサービスのコンテナが全て停止される。

$ docker-compose stop
Stopping php72-apache_phpmyadmin_1 ... done
Stopping php72-apache_php_1        ... done
Stopping php72-apache_mysql_1      ... done

コンテナの稼働状況を確認する。
停止しているコンテナを表示する為に -a オプションを使用します。

$ docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                      PORTS               NAMES
120e4b86b987        phpmyadmin/phpmyadmin   "/run.sh supervisord…"   3 minutes ago       Exited (0) 11 seconds ago                       php72-apache_phpmyadmin_1
bf42cd71d3d4        php:7.2-apache          "docker-php-entrypoi…"   3 minutes ago       Exited (0) 11 seconds ago                       php72-apache_php_1
699f32a6424e        mysql:5.7               "docker-entrypoint.s…"   3 minutes ago       Exited (0) 11 seconds ago                       php72-apache_mysql_1

サービスの開始

docker-compose.yml に記載されているサービスのコンテナが稼働する。
あらかじめ、コンテナが作成されている必要がある。

$ docker-compose start
Starting php        ... done
Starting mysql      ... done
Starting phpmyadmin ... done
$ docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                            NAMES
120e4b86b987        phpmyadmin/phpmyadmin   "/run.sh supervisord…"   8 minutes ago       Up 10 seconds       9000/tcp, 0.0.0.0:4040->80/tcp   php72-apache_phpmyadmin_1
bf42cd71d3d4        php:7.2-apache          "docker-php-entrypoi…"   8 minutes ago       Up 11 seconds       0.0.0.0:8080->80/tcp             php72-apache_php_1
699f32a6424e        mysql:5.7               "docker-entrypoint.s…"   8 minutes ago       Up 12 seconds       3306/tcp, 33060/tcp              php72-apache_mysql_1

コンテナの削除

docker-compose.yml に記載されているサービスのコンテナを停止、コンテナとネットワークが削除される。

$ docker-compose down
Stopping php72-apache_phpmyadmin_1 ... done
Stopping php72-apache_php_1        ... done
Stopping php72-apache_mysql_1      ... done
Removing php72-apache_phpmyadmin_1 ... done
Removing php72-apache_php_1        ... done
Removing php72-apache_mysql_1      ... done
Removing network php72-apache_default
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker SDK for Goでコンテナのログをtailしてみる

こんにちわ

最近DockerのTUI Clientを作っていて、SDKでハマっていたところがあるので、
自分の備忘録として記事に残します。

2019/03/02 追記
HTTP/2の多重化ストリームと書きましたが、
Dockerは独自のフレームを定義してるのでHTTP/2ではなかったです。すいません。

Docker SDKとは

普段Dockerを使っている方なら知っていると思いますが、
Dockerコマンドは実はDocker Engine APIを叩いているだけです。
そのAPIを叩く部分をラッピングして使いやすくしたのでSDKです。

image.png

公式SDKはGoとPythonしかない様ですが、REST APIなのである程度自作はできると思います。
https://docs.docker.com/develop/sdk/

本日は、GoのDocker SDKを使ったコンテナログをtailする時に躓くポイントについて話していきます。

コマンドでコンテナログをtailする

普通にコマンドを実行するとこんな感じになります。

$ docker container logs -f mysql
Initializing database
2019-02-07T03:53:08.512874Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2019-02-07T03:53:09.514164Z 0 [Warning] InnoDB: New log files created, LSN=45790
2019-02-07T03:53:09.647195Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
2019-02-07T03:53:09.716490Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: e24f13bf-2a8b-11e9-897a-0242ac180003.
2019-02-07T03:53:09.718579Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
2019-02-07T03:53:09.719975Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2019-02-07T03:53:12.975444Z 1 [Warning] 'user' entry 'root@localhost' ignored in --skip-name-resolve mode.
2019-02-07T03:53:12.975490Z 1 [Warning] 'user' entry 'mysql.session@localhost' ignored in --skip-name-resolve mode.
2019-02-07T03:53:12.975499Z 1 [Warning] 'user' entry 'mysql.sys@localhost' ignored in --skip-name-resolve mode.
2019-02-07T03:53:12.976376Z 1 [Warning] 'db' entry 'performance_schema mysql.session@localhost' ignored in --skip-name-resolve mode.
2019-02-07T03:53:12.976406Z 1 [Warning] 'db' entry 'sys mysql.sys@localhost' ignored in --skip-name-resolve mode.
2019-02-07T03:53:12.976691Z 1 [Warning] 'proxies_priv' entry '@ root@localhost' ignored in --skip-name-resolve mode.
2019-02-07T03:53:12.977023Z 1 [Warning] 'tables_priv' entry 'user mysql.session@localhost' ignored in --skip-name-resolve mode.
2019-02-07T03:53:12.977056Z 1 [Warning] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode.
Database initialized
Initializing certificates
Generating a RSA private key
...

これをSDKを使って同じ事をします。

SDKを使った場合

SDKではContainersLogsって関数が用意されていて、
それにcontext、コンテナID、オプションを渡すと、レスポンスが返ってきます。
そのレスポンスはdocker側が用意しているdocker/docker/pkg/stdcopy.StdCopyを使用して、標準・エラーに出力します。

package main

import (
    "context"
    "log"
    "os"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
    "github.com/docker/docker/pkg/stdcopy"
)

func run() int {
    c, err := client.NewClientWithOpts(client.WithVersion("1.39"))
    if err != nil {
        return 1
    }

    r, err := c.ContainerLogs(context.Background(), "657814ba450f", types.ContainerLogsOptions{
        ShowStdout: true,
        ShowStderr: true,
        Follow:     true,
    })
    if err != nil {
        log.Println(err)
        return 1
    }

    _, err = stdcopy.StdCopy(os.Stdout, os.Stderr, r)
    if err != nil {
        log.Println(err)
        return 1
    }

    return 0
}

func main() {
    os.Exit(run())
}

ソースはこれだけですが、ちょっとストリーム多重化も関連してくるため、
その知識がないとつまずく方もいるかと思いますので、つまずきポイントについて解説していきます。

躓きポイント

ContainerLogsを使用すると多重化ストリームのレスポンスが返ってきます。
コンテナへのアタッチもこの原理で動いています。

多重化ストリームとは一つのコネクション上で、
複数のHTTPリクエスト&レスポンスのやり取りを行うことができる仕組みとしてHTTP/2で導入されたものです。
詳しくはこちらの資料にわかりやすくまとめてあるので、興味ある方は読んでみてください。

すいません、間違えました。
Dockerでは自前で多重化ストリームを定義していました。
したがってHTTP/2は関係ないです。
ただ、多重化ストリームの考え方同じなはずなので、図のイメージで問題ないと思います。

image.png

Docker側で定められたフレーム定義に従って、
レスポンスを適切に処理して標準・エラー出力しないと、
正しい文字列を得られなくて、先頭に変な文字がついてたりします。

Y2019-03-01T07:14:51.672442Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
Z2019-03-01T07:14:51.673425Z 0 [Note] InnoDB: 5.7.24 started; log sequence number 12440262
E2019-03-01T07:14:51.673943Z 0 [Note] Plugin 'FEDERATED' is disabled.
g2019-03-01T07:14:51.674929Z 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
2019-03-01T07:14:51.717753Z 0 [Note] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them.
N2019-03-01T07:14:51.728152Z 0 [Warning] CA certificate ca.pem is self signed.
U2019-03-01T07:14:51.730623Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
82019-03-01T07:14:51.730701Z 0 [Note] IPv6 is available.
@2019-03-01T07:14:51.730720Z 0 [Note]   - '::' resolves to '::';
H2019-03-01T07:14:51.730740Z 0 [Note] Server socket created on IP: '::'.

Docker側が定めたフレーム定義はこちらになります。

header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}

STREAM_TYPEは

  • 0:stdin
  • 1:stdout
  • 2:stderr

となっています。
1なら、os.Stdoutに出力すると言った制御が必要です。

続いて、SIZE1, SIZE2, SIZE3, SIZE4はビッグエンディアン1としてコンコードされた4バイトデータです。
こちらは、ストリームのフレーム(データの部分)の長さになります。

公式SDKでは以下のロジックで正しくデータを取得できると書いてあります。

  1. Read 8 bytes.
  2. Choose stdout or stderr depending on the first byte.
  3. Extract the frame size from the last four bytes.
  4. Read the extracted size and output it on the correct output.
  5. Goto 1.

上記のロジックに従って、自前で制御するとこんな感じになります。

hdr := make([]byte, 8)
for {
    _, err := r.Read(hdr)
    if err != nil {
        log.Fatal(err)
    }
    var w io.Writer
    switch hdr[0] {
    case 1:
        w = os.Stdout
    case 2:
        w = os.Stderr
    default:
        // error handling
    }
    count := binary.BigEndian.Uint32(hdr[4:])
    dat := make([]byte, count)
    _, err = r.Read(dat)
    fmt.Fprint(w, string(dat))
}

ただ、自前で実装しなくてもDockerが用意している
github.com/docker/docker/pkg/stdcopy.StdCopy(dstout, dsterr io.Writer, src io.Reader)
を使えば簡単に標準・エラー出力できます。

まとめ

今回のようなストリーム型レスポンスを扱う上で、
HTTPの多重化ストリームの仕組みとエンディアンについて知識が必要になってきます。
これらの知識がなかったので、ちんぷんかんぷんでした。

やっとのこと理解できたので、忘れないうちに記事にしました。
今後DockerのSDKを使って何かつくおうと思っている方にとって、何か役に立てればと思います。


  1. エンディアンはCPUによってデータをメモリ上に格納する方法が異なるります。推測になってしまうが、おそらくDocker側はビッグエンディアンに統一させているようです。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LinuxマシンのサービスをDockerに移行するスクリプトを書いた

実行中のLinuxマシンからDockerのベースイメージを生成するスクリプトを書いてみました。

https://github.com/hidakanoko/vm2container

  • このスクリプトは指定されたパッケージの依存性を解決して、パッケージに含まれるコマンドを実行する(プロセスを起動する)のに必要なファイルを集めてDockerのベースイメージを作ります。

  • RPMを使ったシステムなら動くはずですが、今のところCentOS7でしかテストしていません...

  • 実用性は低いような気がしますが、古いマシンをDockerに乗せ換えてとりあえず延命したいようなケースでは役に立つかも?

使い方

スクリプトのダウンロード

# git clone https://github.com/hidakanoko/vm2container.git
Cloning into 'vm2container'...
remote: Enumerating objects: 131, done.
remote: Counting objects: 100% (131/131), done.
remote: Compressing objects: 100% (79/79), done.
remote: Total 131 (delta 68), reused 99 (delta 44), pack-reused 0
Receiving objects: 100% (131/131), 34.22 KiB | 0 bytes/s, done.
Resolving deltas: 100% (68/68), done.

Helpの表示

# cd vm2container/
# bin/v2c -h
usage: vm2container [-h] [-p PACKAGE] [-s] [-l] [-a] [-d DIRECTORY]
                    [-v VERBOSE]

Create docker image from running full Linux environment.

optional arguments:
  -h, --help            show this help message and exit
  -p PACKAGE, --package PACKAGE
  -s, --showDeps
  -l, --listFiles
  -a, --createArchive
  -d DIRECTORY, --directory DIRECTORY
  -v VERBOSE, --verbose VERBOSE
                        ERROR, WARN, INFO, DEBUG

パッケージの依存関係をツリー表示する

-p <PACKAGE>で起動したいコマンドを含むパッケージを指定します。下記サンプルでは/usr/sbin/httpdを起動するためhttpdパッケージを指定しています。

-sで指定されたパッケージの依存関係を表示します。

# bin/v2c -p httpd -s
 * Resolving dependency for httpd...
done!
INFO: Total 115 package(s) found
httpd
    shadow-utils
        audit-libs
            libcap-ng
                glibc
                    glibc-common
                        libselinux
                            pcre
                                glibc [*]
                                libstdc++
                                    libgcc
                                    glibc [*]
                                libgcc [*]
                            glibc [*]
                            libsepol
                                glibc [*]
                                bash
                                    ncurses-libs
                                        libstdc++ [*]
                                        libgcc [*]
                                        ncurses-base
                                        glibc [*]
                                    glibc [*]
                        bash [*]
                        tzdata
                        glibc [*]
                    nss-softokn-freebl

(...omit)

INFO: [*]=Child dependencies are omitted as already described above.

依存性ツリーの中で同じパッケージが繰り返し現れるため、表示済のパッケージの依存関係は省略されます。(末尾に"[*]"がついているパッケージ)

プロセスの起動に必要なファイルを一覧表示する

-lで指定されたパッケージと、その依存パッケージに含まれるすべてのファイルを一覧表示します。(rpm -qlで得られるもの)

# bin/v2c -p httpd -l
 * Resolving dependency for bash...
done!
INFO: Total 41 package(s) found
 * Creating file list of 1 package(s) and its dependent packages...
done!
/
/bin
/bin/egrep
/bin/fgrep
/bin/grep
/bin/sed
/etc
/etc/DIR_COLORS
/etc/DIR_COLORS.256color
/etc/DIR_COLORS.lightbgcolor
/etc/GREP_COLORS
/etc/X11

(...omit)

/usr/share/man/ay/man7 (not found)
/usr/share/man/ay/man7x (not found)
/usr/share/man/ay/man8 (not found)

(...omit)

/var/run
/var/run/setrans
/var/spool
/var/spool/lpd
/var/spool/mail
/var/tmp
/var/yp
INFO: Total 18684 file(s) found, however 13176 file(s) are not present in the file system

パッケージのファイルリストに含まれているものの、ファイルシステム内に存在しないファイルは末尾に"(not found)"がついています。
ユーザーが削除したファイルや、ghostファイルはすでにファイルシステムに存在しないためこのように表示しています。

Dockerのイメージを作成する

-aでDockerイメージを作成します。

Webコンテンツとhttpdのユーザー設定ファイルを含めるため-d <DIRECTORY>オプションで/var/www/htmlと/etc/httpd/conf.dをアーカイブに含めるよう指定しています。

# ./bin/v2c -p httpd -d /var/www/html -d /etc/httpd/conf.d -a
 * Resolving dependency for httpd...
done!
INFO: Total 115 package(s) found
 * Creating file list of 1 package(s) and its dependent packages...
done!
INFO: Total 23237 file(s) found, however 13193 file(s) are not present in the file system
 * Creating archive...
done!
INFO: Archive created in /tmp/archive.tgz

Dockerイメージとしてインポートする

生成したアーカイブはそのままDockerにインポートして、ベースイメージとして利用できます。

コンテナ起動時にパラメータを省略できるよう、エントリーポイントとコマンドパラメーターを含めています。

# docker image import /tmp/archive.tgz v2c-httpd:20190302 -c "ENTRYPOINT [\"/usr/sbin/httpd\"]" -c "CMD [\"-DFOREGROUND\"]"
sha256:7908fb6eb6f50618c688a51556b0348de5948fe0a855aa32b515a74182ca1bbe

コンテナを起動する

# docker run -d --rm -p 8080:80 v2c-httpd:20190302
32409c65c9c5ed96103333461eda513fe1d7c9b842dfc4ad17e22258e155e9e6

ブラウザで http://DOCKERHOST:8080/ にアクセスするとApacheのTest Pageが表示されます。
/var/www/htmlに何かコンテンツを置いているのであればそれにアクセスすることもできます。

ざっくりとした仕組み

Dockerはnamespaceやcgroupなどの技術を使って作成したサンドボックス内でプロセスを起動する技術です。そのためイメージの中に必要なファイルがそろっていればプロセスを起動できるはずです。

Dockerのドキュメントにベースイメージの作り方がありますが、これはdebootstrapでパッケージを展開してアーカイブで固めているだけです。

https://docs.docker.com/develop/develop-images/baseimages/

つまり逆に考えれば、実行中の環境でパッケージの依存性を解決して必要なファイルをすべて集めればDockerイメージを作ることが出来るはずです。(という思いつきからこのスクリプトを組んでみました)

v2cコマンドはパッケージの依存ツリーを解決して(rpm -q --requires, rpm -q --whatprovidesなど)、依存パッケージのファイルをすべて集めて(rpm -ql)、tgzに固めています。

前述のとおりDockerのベースイメージは基本的に必要なライブラリやコマンド、設定ファイルをtarで固めただけなので、このイメージはそのままベースイメージとしてインポート可能です。

TODO

  • パッケージに含まれるドキュメントファイルを除外できるようにする
  • DEBパッケージ対応
  • ベースイメージ + レイヤーイメージを作れるようにする。例えばベースイメージにはコアパッケージを含めておいて、レイヤーイメージにWebサーバーやMariaDBを起動するためのファイルを含めるような感じ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

10分でLinuxのGitLab環境(Docker)を構築してAndroiStudioのソースをPushする

〇この記事について

Linux(Ubuntu)環境で、Docker-Composeに設定を登録し、Docker(仮想環境ツール)を起動して、簡単にローカルのGitLab環境を構築し、Androidのソースを保存するまでの設定方法を記載します。
別にAndroidだけじゃなくて他のソースだろうと管理できますが、一応AndroidStudioで実際にPushする設定まで含めます。

今回はDockerにGitLab公式のイメージがあり、それを利用します。
Dockerって使わなくても直接OSにGitLabインストールすればいいんじゃない?という人もいるかもしれませんが、両方試してみて、Dockerのほうが明らかに管理が楽でした。
コマンドで簡単にGitLabに適した環境が丸ごとダウンロードできてしまう!ソフトウェアのアップデートが簡単にできてしまう!バックアップも簡単!時代の流れは完全にDocker!と思わせるほどです。

Docker-Composeに関しても、Dockerのコマンドをメモっておいてそれを叩けば利用しなくてもよいのですが、Dockerを管理していくならあると便利です。(というかほぼ必須です)

コマンドと公式URLを書いた10分コースと詳細も追加した3時間コースを用意したので好きなほうを読んでください。

〇環境

・OS
Ubuntu 18.04.2 LTS
・Docker
18.09.2
・Docker-Compose
1.23.2
・gitlab-ce
11.7.5
・git
2.17.1
・AndroidStudio
3.3

〇10分で構築する方法

Dockerの設定

・[公式]Get Docker CE for Ubuntu
https://docs.docker.com/install/linux/docker-ce/ubuntu/

・前提ソフトウェアのインストール
sudo -E apt-get install -y apt-transport-https ca-certificates curl software-properties-common

・GPG公開鍵をインストール
sudo -E curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

・aptリポジトリの設定
[x86_64](他のCPUなら公式参照)
sudo -E add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

・Dockerのインストール
sudo -E apt-get install -y docker-ce

・Docker内プロキシの設定
sudo mkdir /etc/systemd/system/docker.service.d
sudo vi /etc/systemd/system/docker.service.d/http-proxy.conf

http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://yyyyy:3128/"

sudo systemctl daemon-reload
sudo systemctl restart docker

Docker-Composeの設定

・[公式]Install Docker Compose
https://docs.docker.com/compose/install/

・[公式]Install GitLab using docker-compose
https://docs.gitlab.com/omnibus/docker/#install-gitlab-using-docker-compose

・ダウンロード
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

・権限変更
sudo chmod +x /usr/local/bin/docker-compose

・dockerと連携するGitLabファイルの保存場所作成
mkdir /docker
mkdir /docker/gitlab/
mkdir /docker/gitlab/config
mkdir /docker/gitlab/logs
mkdir /docker/gitlab/data

・docker-compose.ymlの作成

docker-compose.yml
gitlab:
  image: 'gitlab/gitlab-ce:latest'
  restart: always
  hostname: 'xxxxx.co.jp'
  environment:
    GITLAB_OMNIBUS_CONFIG: |
      external_url 'http://xxxxx.co.jp:10080/gitlab/'
      gitlab_rails['time_zone'] = 'Asia/Tokyo'
  ports:
    - '10080:10080'
    - '10443:443'
    - '10022:22'
  volumes:
    - '/docker/gitlab/config:/etc/gitlab'
    - '/docker/gitlab/logs:/var/log/gitlab'
    - '/docker/gitlab/data:/var/opt/gitlab'

・イメージのダウンロード、docker起動
docker-compose up -d gitlab

GitLabの設定

・初回ログイン
http://xxxxx.co.jp:10080/gitlab/
にアクセス
Username: root
Password: 5iveL!fe

・Registerからアカウント作成

・プロジェクトの作成
(AndroidStudioならInitialize repository with a READMEはしないように)

・CloneボタンのURLをコピー
[http://xxxxx.co.jp:11080/gitlab/user/test.git]

AndroidStudioの設定

・プロジェクト作成

・バージョンコントロールをGitに設定
VCS → Enable Version Control Integration [Git]

・プロジェクトをadd,commit
ソースツリーを[Android] → [Project]に変更
ルートディレクトリを右クリックして、[Git] → [Add]
同じく[Git] → [Commit Directory]

・プロジェクトをpush
VCS → Git → Push
[Define remote]をクリックするとURLを入力できるので
Cronでコピーした[http://xxxxx.co.jp:11080/gitlab/user/test.git]
を入力。
その際にユーザー登録したIDとパスワードを聞かれるので入力。

GitLabで表示確認

http://xxxxx.co.jp:10080/gitlab/
にアクセスしてプロジェクトにソースが反映されているのを確認。

〇3時間で構築する方法

Dockerについて

Linuxで動作する仮想環境ですが、
バーチャルボックスなどと違いOSはインストールせずに既存のOSの上に乗っかる形になるので、
隔離された環境が、容易に作成、コピー、バックアップができ、
公式が作った環境を簡単にダウンロード、アップデートできるのが魅力です。
公式のイラスト通り、船(OS)の上にコンテナ(仮想環境)を積んでいくという印象ですね。
doc.png

Dockerのインストール

・[公式]Get Docker CE for Ubuntu
https://docs.docker.com/install/linux/docker-ce/ubuntu/

・前提ソフトウェアのインストール
sudo -E apt-get install -y apt-transport-https ca-certificates curl software-properties-common

・GPG公開鍵をインストール
GNU Privacy Guard 暗号化ソフトで生成される公開鍵
パッケージが正しい配布先のものかどうかのチェックなどに利用
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

・aptリポジトリの設定
[x86_64](他のCPUなら公式参照)
sudo -E add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

・Dockerのインストール
sudo -E apt-get install -y docker-ce
ちなみに CE(コミュニティエディション)とEE(エンタープライズエディション)がありCEは無償版です。

sudo mkdir /etc/systemd/system/docker.service.d
sudo vi /etc/systemd/system/docker.service.d/http-proxy.conf

http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://yyyyy:3128/"

sudo systemctl daemon-reload
sudo systemctl restart docker

Docker-Composeについて

Docker-Composeはファイルに設定した内容で、Dockerのイメージをダウンロード、コンテナを起動でき、管理が容易になるというものです。
複数のDockerが結びつく場合により便利になります。

Docker-Composeの設定

・[公式]Install GitLab using docker-compose
https://docs.gitlab.com/omnibus/docker/#install-gitlab-using-docker-compose

・ダウンロード
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

・権限変更
sudo chmod +x /usr/local/bin/docker-compose

・Dockerと連携するGitLabファイルの保存場所作成
Dockerは簡単に削除、アップデートすることがあるので、重要ファイルはDocker外に保存します。
mkdir /docker
mkdir /docker/gitlab/
mkdir /docker/gitlab/config
mkdir /docker/gitlab/logs
mkdir /docker/gitlab/data

・docker-compose.ymlの作成

docker-compose.yml
gitlab:
  image: 'gitlab/gitlab-ce:latest'
  restart: always
  hostname: 'xxxxx.co.jp'
  environment:
    GITLAB_OMNIBUS_CONFIG: |
      external_url 'http://xxxxx.co.jp:10080/gitlab/'
      gitlab_rails['time_zone'] = 'Asia/Tokyo'
  ports:
    - '10080:10080'
    - '10443:443'
    - '10022:22'
  volumes:
    - '/docker/gitlab/config:/etc/gitlab'
    - '/docker/gitlab/logs:/var/log/gitlab'
    - '/docker/gitlab/data:/var/opt/gitlab'

保存ディレクトリやymlの作成場所は管理しやすければ、どこでもよいです。
テスト環境が必要でしたらportsやvolumesをずらせば、簡単に複製できます。

・docker-compose.ymlの説明
image:
Dockerのイメージ(元データ)です。
一から自分で作成して、gitlabを入れてもよいのですが、
公式がgitlabを動かすのに最適なイメージを用意してくれています。
https://hub.docker.com/r/gitlab/gitlab-ce/
他にもイメージを利用したければこちらで検索。
https://hub.docker.com/search/?q=&type=image
'gitlab/gitlab-ce:latest'はgitlab-ceの最新版という意味で、イメージを更新すれば、最新版にアップデートしていくことも容易です。

restart:
alwaysにすれば、マシンの再起動時、dockerデーモンの再起動時に再起動してくれます

environment:
gitlabの環境変数を事前に指定できます。
後からでも/etc/gitlab/gitlab.rbを編集して
gitlab-ctl reconfigure
gitlab-ctl restart
でも反映されます。
しかし、手動の変更はコンテナを作り直すたびに初期化されるので、できれば避けたいところです。

ports:
実際のポートとDocerのポートを結び付けています。
10022番ポートに来たら、Docerの22番ポートにつなぎます、という意味です。
なぜGitLabを80で動かさないかというと、GitLabのCronのURLがどうしても80で動かして10080と表示できるように設定できなかったため、
仕方なくDocker内でもHTTPを10080ポートにしました。
HTTPを80で動かしたい人は10080と記載されているところを全部直せばできます。

volumes:
重要フォルダをDocker外に結び付けてDockerを削除しても設定やログがそのまま残るようにしています。
つまりこれらのバックアップさえあればよいということで管理が楽ですね。

・イメージのダウンロード、docker起動
docker-compose up -d gitlab
dockerの起動ですが、イメージがない場合はダウンロードしてきてくれます。

ちなみにDocker-Composeを使わず手動で叩くとこんな感じです。
docker run --detach \
--hostname XXXXX.co.jp \
--publish 10443:443 --publish 10080:10080 --publish 10022:22 \
--name gitlab \
--restart always \
--volume /docker/gitlab/config:/etc/gitlab \
--volume /docker/gitlab/logs:/var/log/gitlab \
--volume /docker/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest

・イメージ確認
docker images

・コンテナ確認
docker ps -a

・コンテナに入る
docker exec -it gitlab /bin/bash

GitLabの設定

・初回ログイン
http://xxxxx.co.jp:10080/gitlab/
にアクセス

・パスワード変更
初回パスワードを入力して、適当に変更
Username: root
Password: 5iveL!fe

・Registerからアカウント作成
作成したアカウントの下にプロジェクトを作成していきます。

・プロジェクトの作成
Initialize repository with a READMEをしてしまうと、一度PullしないといけなくなりAndroidStudioの場合は面倒なことになってしまいます。

・CloneボタンのURLをコピー
[http://xxxxx.co.jp:11080/gitlab/user/test.git]

AndroidStudioの設定

・プロジェクト作成(既存であればそれでよいです)

・バージョンコントロールをGitに設定
VCS → Enable Version Control Integration [Git]

・プロジェクトをadd,commit
ソースツリーを[Android] → [Project]に変更
ルートディレクトリを右クリックして、[Git] → [Add]
同じく[Git] → [Commit Directory]

add,commitする方法は複数あるのでやりやすい方法で行ってください。

・プロジェクトをpush
VCS → Git → Push
[Define remote]をクリックするとURLを入力できるので
Cronでコピーした[http://xxxxx.co.jp:11080/gitlab/user/test.git]
を入力。
その際にユーザー登録したIDとパスワードを聞かれるので入力。
他にもSSHのキーを登録してアクセスする方法もあります。

GitLabで表示確認

http://xxxxx.co.jp:10080/gitlab/
にアクセスしてプロジェクトにソースが反映されているのを確認。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntu向けLinuxカーネルのdebパッケージ作成 (+perf, ftrace)

Ubuntu向けのLinuxカーネル関連debパッケージであるlinux-image, linux-headersに加えてlinux-tools(perf等が含まれる)を作成するための手順/スクリプトについて整理しています。

最新Linuxカーネルをビルドして適用したものの、カーネルバージョンの不一致によりperf, ftrace等を利用できず困ってる人向けです。

背景

Linuxカーネルはバージョンが上がる度に様々な機能、バグフィックス、最適化が加わります。また、パフォーマンスチューニングや解析のために必要なカーネル周りのメトリクス・ツール周りも積極的に強化されるため、新しいLinuxカーネルを積極的に導入&検証する方も多いと思います。

しかし新しいLinuxカーネルをビルドして適用した場合、perf, ftrace等のカーネル周りのイベント等を監視するためのツールもカーネルのバージョンに合わせて更新しなければ利用できなくなります。

apt/yum等のレポジトリに登録されているLinuxカーネルの場合、基本的にそのカーネルバージョンに対応するパッケージ(ex. linux-tools)が提供されているため特に問題はありません。
しかしそれ以外の手段(ex. Linux本家のソースコード、Ubuntu mailine ppa)でLinuxカーネルを適用する場合、perf, ftrace等がデフォルトでは含まれていなかったり、これらを含めるために結構色々な知識や試行錯誤が必要となることが多いです。

Linuxカーネルの最新版を適用しても、perf, ftraceを利用できなければ解析や検証の幅が極めて狭くなってしまいます。

このため本記事では以下のものを利用して、linux-image, linux-headers等のdebパッケージに加えてlinux-toolsのdebパッケージを作成するための「Dockerを活用した手順/スクリプト」について記載しています。

  • Linux本家のLinuxカーネル ソースコード
  • Ubuntu mainline ppaのパッチファイル

前提

  • ビルドマシン環境の前提
    • Ubuntu 16.04 or 18.04
    • Docker 18.09 (おそらく17.xxでも問題なし)
  • ビルド実施者の前提
    • Linuxカーネルのビルド、コンフィグ設定、インストール等ができることを想定。
    • perf, ftrace等のツールの重要性を理解している。
    • プロダクト環境等に導入する場合は、事前に十分な検証を行ったり、リスク評価を行ったりする必要があると十分に理解していることを想定。

ビルド手順

下記gistに手順および資材ファイルを載せています。

https://gist.github.com/yoichiwo7/70f81429813c5ec32cc620a950495b3e

手順はgistのREADME.mdにも記載していますが、簡単に日本語で記載しておきます:

gistにあるDockerfilebuild-kernel-with-perf.shを同じディレクトリにダウンロードします。

ダウンロードしたディレクトリにcdして、下記コマンドを実行してカーネルビルド用のDockerイメージを作成します。何故Dockerを使っているかは簡単に後ろの節で説明しています。

docker build -t kernel-build .

Dockerイメージを作成後、Dockerコンテナを起動してカーネルをビルドします。コマンドの最後のパラメータはLinuxカーネルのバージョンなので、ビルドしたい適切なバージョンに適宜変更してください。

ちなみにLinuxカーネルのビルドには数時間レベルの時間がかかるので注意しましょう。

TARGET_KERNEL_VERSION="4.20.13"
docker run \
    --rm \
    -u $(id -u):$(id -g) \
    -v $PWD:/Output \
    kernel-build $TARGET_KERNEL_VERSION

ビルドが完了すると、同じディレクトリ配下に*.debのLinuxカーネル関連のdebパッケージが配置された状態となります。debパッケージは以下のコマンドでインストールすることができます。(インストール順は重要です)

dpkg -i linux-headers-*
dpkg -i linux-modules-* linux-image-*
dpkg -i linux-tools-*

(補足) ビルド用Dockerイメージを使う理由

Linuxカーネルの各種debパッケージをビルドをするためには様々なUbuntuパッケージが必要となります。さらにUbuntuの16.04/18.04とかDesktop/Serverでも微妙に必要なパッケージ条件が異なる可能性があります。

このためDockerを使わずに様々なバージョンのUbuntu環境でカーネルビルドを実施すると、どうしても試行錯誤を繰り返しがちですし、Ubuntu環境自体に色々なパッケージがインストールされて汚れてしまいます。そして色々入れ過ぎたり設定したりした結果、何が正しいビルド条件なのかが把握できなくなることも珍しくはありません。

このため本手順ではカーネルビルド用のDockerイメージ(ベースイメージをubuntu 18.04に固定)を作成することで「より確実かつ環境を汚さず」にビルドを実施できるようにしています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

neo4jとgremlin-serverをdockerで構築

docker-compose.yml

ポイント

  • neo4jの永続化のためのマウント
  • gremlinの設定ファイルを変更するためのマウント
docker-composer.yml
version: "3.3"
services:
  neo4j:
    image: neo4j
    ports:
      - "7474:7474"
    volumes:
      - ./neo4j-data:/data

  gremlin-server:
    image: tinkerpop/gremlin-server
    depends_on: 
      - neo4j
    ports:
      - "8182:8182"
    volumes: 
      - ./gremlin-conf:/conf/

gremlin-serverの設定ファイル

gremlin-server-neo4j.yamlとneo4j-empty.propertiesの二種類のみを使う。
ただし、前者のファイルは特にいじらないので、置くだけ。

ポイント

  • HAモードで起動(dockerで同時起動なので、embeddedモードは無理?未検証)
  • 一つのneo4jコンテナしか立てないので、neo4jホストのアドレスは種類問わず全て"neo4j" 。

(補足:docker-compose.ymlのdepends_onでneo4jを設定しているので、gremlin-serverから同じ名称で参照できる。たしか、Hostsファイルにneo4jの情報を書いてくれてたはず。)

neo4j-empty.properties
gremlin.graph=org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph
gremlin.neo4j.directory=/tmp/neo4j.server1
gremlin.neo4j.conf.ha.server_id=1
gremlin.neo4j.conf.ha.initial_hosts=neo4j
gremlin.neo4j.conf.ha.host.coordination=neo4j
gremlin.neo4j.conf.ha.host.data=neo4j
gremlin.neo4j.conf.dbms.auto_index.nodes.enabled=true
gremlin.neo4j.conf.dbms.auto_index.relationships.enabled=true

最後にdocker-compose up -dで立ち上げて終了。
gremlin-serverに対してクエリを投げればneo4jに保存される。

参考

gremlin-serverのHAモードについて
http://tinkerpop.apache.org/docs/current/reference/#_high_availability_configuration

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerでのデータベース環境構築in Spring boot(IntellJ)

Spring boot + dockerでデータベース連携するぞ!

初記事。
ご指摘たくさんください。

Spring bootでポートフォリオを作ろうと思った時にdockerでのDB構築に手間取ったのでメモ。

今回のゴール

サンプルプロジェクトにてdockerを用いて構築したデータベース(Mysql)の値を画面へ出力する

・対象読者...

docker初心者
or
開発経験の浅い(1、2年)エンジニア

今回注力する観点

・dockerfileの作成の仕方
・docker上に作成したMySQL環境とspring bootプロジェクトの連携

※dockerの概念などはザックリ説明→とりあえずdockerとアプリケーションを連携するところまで

dockerとは

@kotaro-drさんの記事を載せさせていただきます。
【図解】Dockerの全体像を理解する -前編-
┗ドキュメントが綺麗で初学者でもかなりわかりやすい
【図解】Dockerの全体像を理解する -中編-
┗中編の最初にはデータベースの永続化にも関わってくるデータ管理の話が出てくるので今回は最低そこまでチラ見すればOKです。
ついでに後編も載せておきます。
【図解】Dockerの全体像を理解する -後編-

なぜdockerなのか

・Vurtualboxよりも軽量である←テーマと焦点がズレるため詳しくは割愛。
・開発環境をすぐに用意できる
┗「この端末では動くのに自分の端末では動かない。」ということがなくなる。
┗知り合いに質問したりteratailなどのQAサービスで質問したりするときに自分の今の環境をそのまま相手に渡すことができ、回答が返って来やすくなる。
※今回はローカルマシンにIntelliJとJavaが入っていることを前提に進めます。Javaをdockerに含めることもできますが今回の観点を
「dockerでのMysql環境の構築とアプリケーションとの連携」としているため。
IntelliJとJavaのインストールについては以下に載せます。
■IntelliJ
IntelliJ -for mac
IntelliJ -for Windows
■Java11
Java -for mac
Java -for Windows

早速やってみよう

■環境情報
言語:Java(jdk11)
FW:Spring boot
IDE:IntelliJ
※今回、IDEをIntelliJにしてみました。操作感はほぼeclipseと同じですが、UIがなんかいい感じ。今では世界シェアはeclipseを抜いているとかいないとか。。。
まずはプロジェクトを簡単に作ってみたいと思います。
その前にIntelliJにjdkのパスを登録します。以下リンク内で、【Javaプロジェクトの作り方】を検索すると出てきます。
JDKの登録

今回作成するプロジェクトのtreeです。(画像ですみません)

スクリーンショット 2019-02-24 15.49.49.jpg

今までリンクばかりでしたが、そろそろ自分の言葉を出していきたいと思います。

プロジェクトの作成

今回はデータベースの値を全て出す簡単なモノを作ります。
というか見ればわかるレベルなので3分クッキングパターンで、出来たものが以下になります。
docker(github)
※要所でコメントを入れていますのでもし解釈が間違っている等ありましたらご指摘頂けると助かります。

application.propertiesについて

spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=UTF-8&serverTimezone=JST 
#//demoが今回のデータベース名
spring.datasource.username=root //ユーザ名
spring.datasource.password=p@ssw0rd  //パスワード
spring.jpa.hibernate.ddl-auto=update  //アプリケーション起動時に、Entityに対応するテーブルがなければ作成

こちらはデータベース連携に必要な最低限の設定です。のちに作成するdocker-compose.ymlの内容と合わせる必要がありますので注意してください。

dockerfileの作成

今回はsrcと同じ階層にdockerというフォルダを作成しその中に関連ファイルを作っていこうと思います。
場所についての記述が見つけられなかったため特に指定はないと認識しています。

fockerfile
FROM mysql:8.0  #dockerhubより取得するイメージを指定

RUN /bin/cp -f /etc/localtime /etc/localtime.org
RUN /bin/cp -f /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

COPY ./my.cnf /etc/mysql/conf.d/

RUN mkdir -p /var/log/mysql
RUN chown mysql.mysql /var/log/mysql

COPY:コマンドの左側がローカル側、右側がdockerイメージ側のことを書いております。
RUN:対象のイメージにインストールされているコマンドを実行できる

docker-compose.yml
version: '3'
services:
    mysql:
        build: ./mysql
        environment:
            - MYSQL_DATABASE=demo
            - MYSQL_ROOT_USER=root
            - MYSQL_ROOT_PASSWORD=p@ssw0rd
            - TZ=Japan
        volumes:
            - ./initdb.d:/docker-entrypoint-initdb.d
            - ./dbdata:/var/lib/mysql
        ports:
            - "3306:3306"

↑コロン(:)で区切られている場合

・左側がホスト側、右側がコンテナ側のパスを表す
・初期データ投入→initdb.dディレクトリに最初に読み込むsqlファイルを入れる
永続化→dbdataに処理をするごとにデータ相当のファイルがどんどん入ってくる

docker-composeを起動させよう

プロジェクト上のdocker-compose.ymlを右クリックし「再生」をします。
スクリーンショット 2019-03-01 22.49.47.jpg
すると、さっき書いたdockerfiledocker-compose.ymlを解釈してせっせか環境構築が始まります。
以下のように'Compose: docker' has been deployed successfully.と出たら完成です。
スクリーンショット 2019-03-01 22.53.15.jpg

では早速、データベースが出来上がっているかコンテナに入って確認してみます。
ターミナル(Windowsの場合はコマンドプロンプト)でプロジェクトのディレクトリへ移動します。
その中で
docker psコマンドで現在のコンテナの稼働状況を確認します。
実行後が下図です
スクリーンショット 2019-03-02 0.18.36.jpg

mysqlのイメージができていることがわかります。
起動にはこちらのCONTAINER IDもしくはNAMESを使います。今回はCONTAINER IDを使って起動してみます。

docker exec -it 【CONTAINER ID】 bashでコンテナに入ります。
root@37c06170b19b:/#こんな感じのターミナル(コマンドプロンプト)になっていれば入れています。
この画面よりrootユーザでMysqlへ接続します。
mysql -u root
今回はパスワードをp@ssw0rdとしてます。
以下のようにmysqlへ接続
スクリーンショット 2019-03-02 0.40.51.jpg

use demoで今回のサンプルデータベースを指定。あとは適当にsqlをうって確認します。初期データとしてはuserテーブルが入っていますので。
select * from user;
スクリーンショット 2019-03-02 0.46.40.jpg
テーブルの中身を確認できました。

あとは自分のショボいサンプルプロジェクトをDockerApplicationから実行すると...
以下のようにデータベースとの連携に成功しました。
スクリーンショット 2019-03-02 0.52.29(2).jpg

このようにdockerを使えば環境ごと相手に渡すことができるのでわざわざ相手にデータベースのセットアップやデータの投入をさせずに済みます。
dockerの知識はまだまだ浅いですが、これからどんどん使われていく事になると思いますので、積極的に使っていきたいものです。

次回は、Spring bootで認証画面を試してみたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails要らず、CGIとRubyでソースコードをフローチャートにするツール作成

きっかけは怠惰なお気持ちでした。ということで、こんなの作ってみました。よかったら、ご覧ください。

要は、フォームに入力されたRubyのソースコードを、フローチャートにしてくれる、というもの。

class_worker.gif

具体的には、以下のソースコードが

class Worker
    def initialize(hungry:)
      @hungry = hungry
    end

    def next_action
      if hungry?
        :eat
      else
        :work
      end
    end

    def hungry?
      @hungry
    end
  end

こんな画像になって出てくる。

source_code.png
ソースコードのフローチャート化のために、RubyのGemvisualize_rubyとグラフ描画してくれるGraphvizを使っています。

きっかけは怠惰なお気持ちでした(T_T)

  • 業務の中で仕様書になっていないソースコードを読んで、読んで、理解して、フローチャートにして、要件詰めて、また読んでが面倒に思えた。
    • 読むだけなら、まだいいんですが、他の人と共有とかを考えると可視化していく必要があった
    • 1回ならいいんだけれど、いろんなところでそれが発生していた
    • どんどん変化していく類のものだったときに、仕様書にしてもメンテされない
あと普段Railsを使うことが多いのですが、乳離というか、Rails離れもしたいというお気持ちでした
  • Railsにはいつもお世話になっており、細かいことを気にしなくても、ワタシが気持ちよく働ける環境を作ってくれています
    • が、いっぽうで、それゆえに根本的なRubyという言語やWebサービスがどう動いているのかの理解が浅いままになっちゃているな、とも思うようになった。
    • ミニマムでやりたいことだけをやるとしたときに、なにがあればいいんだろうかっていうのも知りたかった。恥ずかしながら、たぶんRailsなしでは飛べない小鳥ですので。
フローチャートに自動でしてくれるやついないかなって探していたら、街角でばったり出くわしたのがvisualize_rubyでした。
  • 有り難いと思いながら、卑屈な人間なので
    • 簡単に自分の環境で実装ができたのですが、環境依存とかで設定が面倒だなって思い
    • コンソールからイジルの、絶対みんなできないよ〜って思い

そうだ!環境に依存しないDockerでRailsを使わない(CGIとRuby)でブラウザからフォーム入力ができて、描画してくれるツールを作ってみようと決心したのでした。

こちらが該当のリポジトリ、名付けてVisualizeSrc!!
ざっくり取り上げると、以下のような構成で作ってみました。詳細な中身はリポジトリをご覧ください。基本的には、リポジトリを各人のローカル開発環境にpullしてもらって、ビルドしてもらえればlocalhostのport80で動くような設定をしています。

ファイル構成

/var配下の処理スクリプト達
├── www
│   ├── cgi-bin
│   │   ├── Gemfile
│   │   ├── Gemfile.lock
│   │   ├── result.rb ...フォームから値を受け取ってモジュールに渡す
│   │   ├── source_code.png ...作成される画像データ
│   │   └── visualize_mod.rb ...画像を作るモジュール
│   └── html
│       └── form.cgi ...フォームから入力値を受け取る

/etc配下の設定ファイル達
├── conf
│   ├── httpd.conf ... PortやAliasの設定
├── conf.d
│   ├── cgi-enabled.conf ... CIGでRubyファイルが処理できるように設定

ちなみにrbenvを使って管理しており、Gemは以下のパスへ
/usr/local/rbenv/versions/2.3.8/lib/ruby/gems/2.3.0/gems/

環境

- Dockerfile
- CENTOS:7
- Apache
    - 変更した設定(Dockerでイメージビルドするときに差し替えました)
        - httpd.conf
        - cgi-enabled.conf
- Ruby:2.3.8
    - 使ったライブラリ
        - parser
        - visualize_ruby
- 詳細はDockerfileを!

使い方はこんな感じ。

1. 該当リポジトリを各環境へpull 

git pull https://github.com/taishinagasaki/visualize_src.git

2. Docker imageの作成 

docker build -t repository_name/image_name:tag_name . --no-cache=true

3. できたイメージを確認

docker images

4. dockerのイメージは以下の特権モードで起動する。ポートは80と80を繋げる。 

docker run --privileged -d -p 80:80 --name container_name repository_name/image_name:tag_name /sbin/init

5. containerが立ち上がっていることを確認する。statusがUPになればOK。 

docker start <container_id>

6. 立ち上がっていればcontainer idを指定して起動 

docker exec -it <container_id> /bin/bash

7. apacheの起動 

systemctl start httpd

8. apacheの起動を確認 

systemctl start httpd

9. ブラウザから localhost/form.cgiへアクセス
使い方は該当リポジトリのREADME.mdに記載しております。

各工程と、助けてくれた資料達

作業内容 資料名
ApacheのインストールからCGI設定まで Apache httpd : インストール設定
RubyをCGIで動かす設定まで Apache httpd : Ruby を利用する
フォーム入力値をRubyファイルで受け取る [Linux][Ruby]ApacheでRubyのCGIを動かす方法
Dockerでsystemctlを使えるようにする CentOS 7のDockerコンテナ内でsystemdを使ってサービスを起動する
Dockerでイメージ作ってコンテナを立ち上げる Dockerコマンドメモ

ハマったこと

Shebangという、インタプリタの指定にハマってしまいました。

シバンまたはシェバン (英: shebang) とはUNIXのスクリプトの #! から始まる1行目のこと。起動してスクリプトを読み込むインタプリタを指定する。

恥ずかしながらShebagの存在すら知らず、インストールしたgemを一括で取り込むためにrequire 'bundler/setup'を実行しても延々とエラーが出続ける、というもので、これに関してはデバッグ方法もわからずでした。ググってもなかなかなく、根本的な理解がなってないな〜ということを改めて知りました。
また後日、投稿したいと思います。
[追記: 2019/03/02] `require': cannot load such fileエラーをインタプリタ指定から探る ~ファイル1行目のshebang設定~...shebang設定について言及

まだできてないこと/TODO

  • Web化してもいいかなっておもったんですがセキュリティ周りの設定が間に合わず(怖かったので)、またの機会に持ち越しとしました。
  • DockerfileのCMD複数指定を実現する。
    • CMDでshell scriptを指定してあげるとできるとおもっていたが、できず。
    • どうにかやってみたい。
  • VIMで環境を整えたい。

学び

  • Railsから離れたり、いつも使っている高機能エディタから離れることでより根本理解が深まった印象。
  • MW(Apache)やOS層も普段は殆ど触らないので勉強することが多かった。
  • 実はQiita投稿も初めてなので、その他「初めて」が多くてよかった。

次にやりたいこと

  • TODOを潰す
  • Dappに触ってみる

お読み頂きありがとうございました。
なにか間違っていたり、ベターな方法がある場合はご教示いただけると幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む