LoginSignup
3
0

More than 1 year has passed since last update.

突然Dockerコンテナ作成してみる話 DockerBuildしよう

Last updated at Posted at 2021-12-25

Dockerコンテナを作ろう

さてここまでの作業で、コンテナの中で動作するApplicationを作成、修正することが可能になりました。ここからApplicationをコンテナimageに入れる方法に話題を移します。今回はコンテナビルド用の環境を作成し、コンテナをビルドするところまで一気に駆け抜けます。ちょっと長くなりますが、よろしくお願いします。

前提

作業スコープ

今回の作業スコープです。広いなー
ProjectImages-Docker環境.drawio.png

作業の流れ

作業スコープだけではよくわからないので、今回の作業の流れを整理します。
ProjectImages-2部構成.drawio.png

  1. Podman 環境を作って
  2. コンテナをビルドして
  3. 実行してみる

って流れです。

ん?Podman?聞きなれないな?

PodmanはOSSのコンテナビルド、実行ソフトウェアです。のOCIコンテナiamgeを作成し実行します。Dockerからの移行を容易にするため、Dockerコマンドと同じように使えるように配慮されています。

Dockerでよくね? 普通にそう思いませんか?私もそう思っていました。しかし、DockerはあくまでDocker社のものです。彼らに利益が泣ければ存続不可能です。マネタイズが必要です。Docker デスクトップは一定の条件下で有料利用となります。そして弊社・・・・対象なんですよね。なので、自分の勉強のために Dockerデスクトップではなく、Podmanを利用してみました。

1. Podmanビルド環境を作ろう

では、早速Podmanビルド環境を作っていきます。
ProjectImages-環境説明.drawio.png

導入環境

No. ソフトウェア 備考
1 Ubunut ゲストOS verion 20.0.4 LTS
2 JDK SpringBoot ビルド用
3 Maven SpringBoot ビルド用
4 podman Docker(podman)コンテナビルド用
5 ansible 環境構築用
6 git Playbook取得用

Ubuntu 導入

Install

コマンドプロンプトを起動して以下のコマンドを実行する

>winget install "Ubuntu 20.04 LTS"
見つかりました Ubuntu 20.04 LTS [9N6SVWS3RX71] バージョン Unknown
このパッケージは Microsoft Store から提供されています。
…
発行元は、お客様がインストール前に上記の情報を表示し、契約に同意することを必要としています。
使用条件に同意しますか?
[Y] はい  [N] いいえ:Y←入力後Enter
…
インストールが完了しました

インストール完了後、Ubuntuを起動する。
WS000024.JPG

初期起動時の設定

  • usernameを決定する※1
    WS000025.JPG

  • passwordを決定する※2
    WS000026.JPG

  • passwordを確認する※3

以後sudo のたびにこのパスワードが必要になりますので、大切に保管(記憶)してください。

はい。Ubuntuが起動しました。これからはいつでもこのLinux環境を好きなだけ使えます。楽しんでください。

Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: shupeluter ※1
New password: ※2
Retype new password: ※3
…
Installation successful!

初期パッケージ導入

起動したUbuntuのターミナルで以下を実行

$ sudo apt-get update
[sudo] password for shupeluter:★パスワードを入力する
…
Get:42 http://archive.ubuntu.com/ubuntu focal-backports/multiverse amd64 c-n-f Metadata [116 B]
Fetched 20.9 MB in 6s (3354 kB/s)
Reading package lists... Done

$ sudo apt-get install -y ansible git

初期パッケージ動作確認

起動したUbuntuのターミナルで以下を実行

$ git --version
$ ansible --version

★それぞれのversion情報が出力されることを確認

local プロビジョニング

コンテナ構築の前提ソフトウェアをAnsibleで導入する

Playbook取得

Ubuntuターミナルで以下を実行

$ git clone -b podmanbuild https://github.com/atowaito/4qiita.git
…
Unpacking objects: 100% (44/44), 5.96 KiB | 1.19 MiB/s, done.

$ cd 4qiita

設定変更

ユーザID変更

以下のファイルを編集し、usernameを※1で設定した値に変更する

No. ファイル名 変数名
1. group_vars/all USER_NAME
2. main.yml user

Playbook実行

Ubuntuターミナルで以下を実行

cd ~/4qiita
$ ansible-playbook main.yml --ask-become-pass
BECOME password:★passwordを入力後Enter
... 
TASK [02.installPodman : パッケージインストール] ******************************************************************
changed: [localhost]

PLAY RECAP *********************************************************************************************
localhost                  : ok=9    changed=8    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

動作確認

以下のコマンドを実行して、環境を確認

source ~/.bashrc
★以下バージョン情報が出力されることを確認する。

$ java --version
$ $JAVA_HOME/bin/java --version
$ mvn --version 
$ podman --version

PlayBookの内容をちょっと解説しちゃうよ

今回の手順では環境構築にAnsibleを利用している。Ansinleは人気のプロビジョニングツールで、サーバ等の環境を自動的に構築する。それこそ、1台~数百台まで、全てまったく同じ環境にするのが得意。
たとえばLinuxサーバを初期設定するとなると真っ先にシェルスクリプトを思い出すが、シェルスクリプトを利用する単純な構築自動化では、「2度目実行する場合」想定することが難しい。例えばuser addをシェルで実行した場合、「既にそのuserが存在する場合」を考慮しない限り、該当処理を実行した瞬間に、スクリプトは異常終了してしまう。Ansible等のプロビジョニングツールではこの点が考慮されていて、「何度実行しても同じ結果」になるように冪等性がツール側で最大限に考慮されている。

さて、ファイル構成を見てみよう。

ファイル構成と役割

ディレクトリ 役割
├── ansible.cfg プレイブックの設定
├── group_vars プロビジョニング対象サーバ全体もしくは種別毎にで共有する変数
│   └── all
├── inventory Ansible Playbook自体の稼動環境の定義
│   └── hosts 構成対象サーバの情報
├── main.yml playbook本体
└── roles Ansible Roleの格納ディレクトリ
    ├── 01.settings4Java Java関連の設定
    │   ├── tasks
    │   │   └── main.yml
    │   └── vars
    │       └── main.yml
    └── 02.installPodman Podmanの導入

それぞれのファイルで何をやっているのか

main.yml

main.yml
- hosts: localhost                 ★対象ホスト
  user: shupeluter                 ★対象ホストにこのユーザでログインして
  become: true                     ★sudo するかな? するよ!!(true)
  gather_facts: true 
  roles:                           ★roles配下の以下のプレイブックを呼び出すよ
    - 01.settings4Java            ★後述
    - 02.installPodman            ★後述

ここでのポイントはbecome: true パッケージのインストールをしなくてはならなかったりするので、管理ユーザで実行したい。ただしWSLでは「パスワードなしsudo」はデフォルトNGになっているので実行時に--ask-become-passを指定してパスワード入力を有効にする必要がある。通常複数台での構築時にはうざすぎるのでsudoresを変更して、パスワードなしsudoを許可する処理を最初に流しておく。

roles/01.settings4Java

java関係のパッケージ導入。ユーザ設定実施するためのrole。まずは変数から。注意。ここでは何かしら意味があるように読めるが、ただの変数定義なので、これ自体は何もしない。(あたり前だけど。)

vars/main.yml
---
# vars file for roles/01.settings4Java
pkgs:
  - openjdk-17-jdk
  - maven
  - unzip
## 導入パッケージの一覧。リスト型で表現

JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
## 各ユーザに設定するJAVA_HOMEの値。

M2_HOME: /opt/apache-maven-3.8.3
### Maven導入ディレクトリ。。しまったこれも変数で組み立てるべきだ!!

MAVEN_VERSION: 3.8.3
### Mavenのバージョン。バージョン変わるだけでいろいろめんどいので組み立て変数に。そのくせM2_HOMEはそのままトホホ

MAVEN_URL: "https://archive.apache.org/dist/maven/maven-3/{{MAVEN_VERSION}}/binaries/apache-maven-{{MAVEN_VERSION}}-bin.zip"
### Maven導入元URL

ENVS:
    - {name: "JAVA_HOME", value: "{{JAVA_HOME}}"}
    - {name: "M2_HOME", value: "{{M2_HOME}}"}
### ユーザ導入環境変数

変数を定義したので、本体を見てみます。

task/main.yml
- name: "パッケージインストール"
  apt:
    state: present
    pkg:
      "{{pkgs}}"

まずは利用するパッケージの導入。ubuntuはdebian系なので、パッケージマネージャはaptです。注目してほしいのは。stateこのパッケージをinstallするわけではないのが世界観の全てです。「状態」を定義しています。installだと今導入されているか、されていないか考えなければなりませんが、stateであれば「状態」としてpresetにするよと宣言しているわけです。最近はパッケージ関連は引数というかパラメータにリスト型を引き受けてくれるようになりましたが、以前はwith_itemsで回していました。

task/main.yml
- name: Unarchive a file that needs to be downloaded (added in 2.0)
  unarchive:
    src: "{{MAVEN_URL}}"
    dest: "/opt"
    remote_src: yes

マニュアルからほぼコピペ(笑){{MAVEN_URL}}のURLから圧縮ファイルを持ってきて、/optに展開してねって内容。

task/main.yml
- name: "環境変数の設定"
  lineinfile:
    backup: true
    regexp: "^export {{item.name}}"
    path: "/home/{{USER_NAME}}/.bashrc"
    line: "export {{item.name}}={{item.value}}"
  with_items: "{{ENVS}}"

ユーザに環境変数を設定していきます。with_itemsは設定された値(リスト)をループさせて実行するということ。このとき対象の情報はitem変数に格納されます。今回はディクショナリを引数に持つので、値を引き出す際にitem.name item.valueとそれぞれのキー値で引き出しているのが特徴的です。

lineinfileは対象のファイルにregexpに該当する行がなければ対象ファイルにlineで指定した値を追加します。対象のファイルの状態が不定な場合に利用します。決まっているのならtemplateが妥当でしょう。今回はJAVA_HOMEとM2_HOMEを入れています。cat ~/.bashrcしてみてください。
また、backup:trueも見逃せないポイントです。こうしておくことで、ファイルが自動で日付付きバックアップされます。ls ~/.bashrc*してみてください。変更前の物がバックアップされているはずです。

あ、変数展開する場合、""で囲むのがAnsibleのお約束なので、気を付けてください。

02.installPodmanの内容は割愛します。ここまでの説明とほぼ同じなので興味があればご覧ください。大したことはやっていません。

環境お掃除

いらないものをため込むと、運用にこまるので、利用し終わったPlaybookは作っと消します。

$ cd ..
$ rm -fr 4qiita
$ ls 
    ★4qiitaが無くなっていることを確認

2. Podmanビルド

** さぁビルドを始めよう **

うーんこのネタ、見飽きたな。。

VS CodeからWSL上のLinuxにアクセスする

次のコマンドをubuntuで実行する1

$ mkdir workspace
$ cd workspace
$ code .

注意:このコマンドはWSL拡張機能が入っていないと動作しません。あらかじめ導入ください。

VS Code でターミナルを開く

メニューバーのターミナルから、「ターミナル」⇒「新しいターミナル」を選択します。

右下にターミナルウィンドウが開き、Linux標準のbashが動作していることがわかります。

Git HubからリポジトリをCloneする。

以下を、ターミナルウィンドウで実行する。

$ git clone https://github.com/atowaito/sampleapi.git api★
Cloning into 'api'...
remote: Enumerating objects: 67, done.
remote: Counting objects: 100% (67/67), done.
remote: Compressing objects: 100% (37/37), done.
remote: Total 67 (delta 19), reused 66 (delta 18), pack-reused 0
Unpacking objects: 100% (67/67), 13.65 KiB | 1.52 MiB/s, done.

★は前回のリソースを格納したご自身のリポジトリのURLを利用してください

まずはSpring Applicationをつくる

$ mvn -f api/spring-server/pom.xml package

[INFO] Scanning for projects...


[INFO] 
[INFO] ---------------------< io.swagger:swagger-spring >----------------------
[INFO] Building swagger-spring 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] --- spring-boot-maven-plugin:2.1.16.RELEASE:repackage (default) @ swagger-spring ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.970 s
[INFO] Finished at: 2021-12-08T00:00:42+09:00
[INFO] ------------------------------------------------------------------------
$ ls api/spring-server/target/*.jar
api/spring-server/target/swagger-spring-1.0.0.jar

Dockerfileを作ろう

VSCodeでDockerfileを作成します。

#ベースイメージの指定
FROM docker.io/library/openjdk
#ローカルに生成したファットJARをイメージ内にコピー
COPY api/spring-server/target/swagger-spring-1.0.0.jar /tmp
#コンテナ起動時の自動起動設定を追加
ENTRYPOINT java -jar /tmp/swagger-spring-1.0.0.jar

もうまんまですね。(笑

docker Buildをしよう

$ cd ~/workspace
$ podman build . -t mycontainer

3. Podman Run

docker runで遊んでみよう

$ podman run -p 8080:8080 mycontainer


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v2.1.16.RELEASE)

2021-12-07 21:56:32.475  INFO 1 --- [           main] com.qiita.api.Swagger2SpringBoot         : Starting Swagger2SpringBoot v1.0.0 on c01820c35f58 with PID 1 (/tmp/swagger-spring-1.0.0.jar started by root in /)
2021-12-07 21:56:32.477  INFO 1 --- [           main] com.qiita.api.Swagger2SpringBoot         : No active profile set, falling back to default profiles: default
2021-12-07 21:56:33.340  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-12-07 21:56:33.366  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-12-07 21:56:33.366  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.37]
2021-12-07 21:56:33.431  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/v1]     : Initializing Spring embedded WebApplicationContext
2021-12-07 21:56:33.431  INFO 1 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 911 ms
2021-12-07 21:56:33.801  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-12-07 21:56:34.049  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path '/v1'
2021-12-07 21:56:34.050  INFO 1 --- [           main] com.qiita.api.Swagger2SpringBoot         : Started Swagger2SpringBoot in 1.859 seconds (JVM running for 2.195)
2021-12-07 21:57:18.434  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/v1]     : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-12-07 21:57:18.434  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-12-07 21:57:18.437  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 3 ms

さて無事起動したのでブラウザからhttp://localhost:8080/v1にアクセスします。いつもの画面で恐縮ですが。。。
WS000038.JPG

おめでとうございます。Docker Imageを自分で作成し実行することができました。

まとめ

今回は盛りだくさんでした

  • WSLでUbuntuが使えるようになったよ
  • Ansibleで自動構築できるようになったよ
  • Dockerファイルを自分で作れるようになったよ
  • Podman Buildできるようになったよ
  • Podman runできるようになったよ

いやーほんと駆け足ですまん。

免責事項

この資料は、本作業を行うために作成したものであり、本作業によって生じた損害については一切の責任を負いません。

<<前の記事   お品書き


  1. Git Hubの認証にはUser/Passwrdではできません。WindowsであればOSとブラウザがうまく橋渡ししてくれますが、LinuxではToken取得したりわりと面倒です。ブラウザを使って認証できるメリットを考えてVS Codeでターミナルを使います。 

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0