docker imageの作成手順

### 前準備
ubuntu20.04にdockerがインストールされている状態

$ sudo docker pull centos/httpd
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos/httpd latest 2cc07fbb5000 2 years ago 258MB

ホストの8080ポートで起動
$ sudo docker run –publish=8080:80 centos/httpd

src/index.htmlファイルをコンテナのvar/www/htmlフォルダにコピー
$ sudo docker ps
$ sudo docker cp src/index.html 2d1b560b580e:/var/www/html/index.html

動作確認
http://192.168.34.10:8080/

$ sudo docker stop 2d1b560b580e
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2d1b560b580e centos/httpd “/run-httpd.sh” 7 minutes ago Exited (137) 11 seconds ago festive_sanderson

コンテナからimage作成
$ sudo docker commit festive_sanderson hpscript_test
$ sudo docker images;
REPOSITORY TAG IMAGE ID CREATED SIZE
hpscript_test latest 926a6d6c6a60 7 seconds ago 258MB
centos/httpd latest 2cc07fbb5000 2 years ago 258MB

OK
このイメージをAWS ECRにpushしたい。
やりたいことの1/3ぐらいは出来た。

ECSの登録方法

1.タスク定義の登録(コンテナの設定)
2.タスクの実行環境となるクラスターの作成(EC2, VPC, セキュリティグループなど)
3.サービスの作成(タスクとクラスターを紐づける)
4.EC2が生成される

コンテナの設定のところを、独自のコンテナで作りたい。
どうやらECRにimageをpushして、そのimageをそのまま使うようだ。

AWS ECRとは

ECSとはElastic Container Registryの略、Dockerのコンテナイメージを保存しておくレジストリ

Edit permission

$ chmod 400 KEYPAIR.pem
$ ssh -i KEYPAIR.pem ec2-user@PublicIP
$ docker pull amazon/amazon-ecs-sample
Using default tag: latest
latest: Pulling from amazon/amazon-ecs-sample
72d97abdfae3: Pull complete
9db40311d082: Pull complete
991f1d4df942: Pull complete
9fd8189a392d: Pull complete
Digest: sha256:36c7b282abd0186e01419f2e58743e1bf635808231049bbc9d77e59e3a8e4914
Status: Downloaded newer image for amazon/amazon-ecs-sample:latest
docker.io/amazon/amazon-ecs-sample:latest
$ REPOSITORY=your-repository-uri
$ docker tag amazon/amazon-ecs-sample:latest $REPOSITORY
$ EC2_REGION=`wget -q -O – http://169.254.169.254/latest/meta-data/placement/availability-zone | sed s/.$//`
$ `aws ecr get-login –region $EC2_REGION –no-include-email`
$ docker push $REPOSITORY

ECS
-> Task definition -> EC2

{
  "family": "ecs-demo",
  "containerDefinitions": [
    {
      "volumesFrom": [],
      "memory": 128,
      "extraHosts": null,
      "dnsServers": null,
      "disableNetworking": null,
      "dnsSearchDomains": null,
      "portMappings": [
        {
          "hostPort": 80,
          "containerPort": 80,
          "protocol": "tcp"
        }
      ],
      "hostname": null,
      "essential": true,
      "entryPoint": null,
      "mountPoints": [],
      "name": "ecs-sample",
      "ulimits": null,
      "dockerSecurityOptions": null,
      "environment": [],
      "links": null,
      "workingDirectory": null,
      "readonlyRootFilesystem": null,
      "image": "YOUR-REPOSITORY-URI:latest",
      "command": null,
      "user": null,
      "dockerLabels": null,
      "logConfiguration": null,
      "cpu": 0,
      "privileged": null
    }
  ],
  "volumes": []
}

ECSCluster

ECRからpushしてimageを作ることが出来る

なるほど、ECSとECRはなんと無くわかったので、後は実践するのみですね。

AWS ECSを始める

ECSとはDockerを簡単に実行、停止、管理できるサービス

management console ECS

Task Definition
create task definition -> EC2 -> json

{
  "family": "myContainer",
  "containerDefinitions": [
    {
      "volumesFrom": [],
      "portMappings": [
        {
          "hostPort": 80,
          "containerPort": 80
        }
      ],
      "command": null,
      "environment": [],
      "essential": true,
      "entryPoint": null,
      "links": [],
      "mountPoints": [
        {
          "containerPath": "/usr/local/apache2/htdocs",
          "sourceVolume": "my-vol",
          "readOnly": null
        }
      ],
      "memory": 300,
      "name": "simple-app",
      "cpu": 10,
      "image": "httpd:2.4"
    },
    {
      "volumesFrom": [
        {
          "readOnly": null,
          "sourceContainer": "simple-app"
        }
      ],
      "portMappings": [],
      "command": [
        "/bin/sh -c \"while true; do echo '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p>' > top; /bin/date > date ; echo '</div></body></html>' > bottom; cat top date bottom > /usr/local/apache2/htdocs/index.html ; sleep 1; done\""
      ],
      "environment": [],
      "essential": false,
      "entryPoint": [
        "sh",
        "-c"
      ],
      "links": [],
      "mountPoints": [],
      "memory": 200,
      "name": "busybox",
      "cpu": 10,
      "image": "busybox"
    }
  ],
  "volumes": [
    {
      "host": {
        "sourcePath": null
      },
      "name": "my-vol"
    }
  ]
}

create

### Cluster
ECS Cluster -> Create
Launch type: EC2

Jsonでupdateできる。
とりあえず触ってみたという感じか。

Getting startedでECSを触ってみる

さくらレンタルサーバーにPython3とPip3を入れる手順

さくらレンタルサーバーにPython3をPip3を入れて動かそうとすると、
ModuleNotFoundError: No module named ‘_ctypes’ となるので、
あらかじめlibffiをインストールする必要がある。

### libffiインストール
mkdir -p ~/work/libffi
cd work/libffi
wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz
tar xvfz libffi-3.2.1.tar.gz
cd libffi-3.2.1
./configure –prefix=$HOME/local/libffi/3_2_1
make
% mkdir -p ~/local/include
% ln -s $HOME/local/libffi/3_2_1/lib/libffi-3.2.1/include/ffi.h $HOME/local/include/
% ln -s $HOME/local/libffi/3_2_1/lib/libffi-3.2.1/include/ffitarget.h $HOME/local/include/
% mkdir -p ~/local/lib
% ln -s $HOME/local/libffi/3_2_1/lib/libffi.a $HOME/local/lib/
% ln -s $HOME/local/libffi/3_2_1/lib/libffi.la $HOME/local/lib/
% ln -s $HOME/local/libffi/3_2_1/lib/libffi.so $HOME/local/lib/
% ln -s $HOME/local/libffi/3_2_1/lib/libffi.so.6 $HOME/local/lib/
% mkdir -p ~/local/lib/pkgconfig/
% ln -s $HOME/local/libffi/3_2_1/lib/pkgconfig/libffi.pc $HOME/local/lib/pkgconfig/

% cd ~/
% vi .cshrc
// パスを最終行に追加

setenv  LD_LIBRARY_PATH $HOME/local/lib
setenv  PKG_CONFIG_PATH $HOME/local/lib/pkgconfig

% source ~/.cshrc
% rehash

### Python3インストール
% mkdir -p ~/work/python3
% cd ~/work/python3
% wget –no-check-certificate https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
% tar zxf Python-3.9.0.tgz
% cd ./Python-3.9.0
% ./configure –prefix=$HOME/local/python/ –with-system-ffi LDFLAGS=”-L $HOME/local/lib/” CPPFLAGS=”-I $HOME/local/include/”
% make
% make install

% cd ~/
%vi .cshrc
// 最終行に以下を追加

set path = ($path $HOME/local/python/bin)

% source ~/.cshrc
% rehash

% python3 –version
Python 3.9.0
% pip3 –version
pip 20.2.3

$ pip3 install ${package}

libffiが無くて、何度もNo module named ‘_ctypes’となり、焦りました。

[Python] 画像を圧縮

まず画像を用意します。

#! /usr/bin/python3
# -*- coding: utf-8 -*-
from PIL import Image
from io import BytesIO
import os

COMPRESS_QUALITY = 30

path = "./src"

images = os.listdir(path)

for image in images:
	if image.endswith('.jpg'):
		with open("./src/" + image, 'rb') as inputfile:
			im = Image.open(inputfile)
			im_io = BytesIO()
			im.save(im_io,'JPEG', quality=COMPRESS_QUALITY)
		with open("./src/comp_" + image, mode='wb') as outputfile:
			outputfile.write(im_io.getvalue())
	if image.endswith('.jpeg'):
		with open("./src/" + image, 'rb') as inputfile:
			im = Image.open(inputfile)
			im_io = BytesIO()
			im.save(im_io,'JPEG', quality=COMPRESS_QUALITY)
		with open("./src/comp_" + image, mode='wb') as outputfile:
			outputfile.write(im_io.getvalue())
	if image.endswith('.png'):
		with open("./src/" + image, 'rb') as inputfile:
			im = Image.open(inputfile)
			im_p = im.convert('P')
			with open("./src/comp_" + image, mode='wb') as outputfile:
				im_p.save(outputfile)

我ながらよく出来ています。

[CSS] width 100%で縦横比を固定

heightを0にして、padding-topを%で指定する

Sass

.v-box {
	width: 100%;
	height: 0;
	padding-top:75%;
	background-color: gray;
}

html

<div class="columns">
				<div class="column">Ch1<br><div class="v-box"></div><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p></div>
				<div class="column">Ch2<br><div class="v-box"></div><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p></div>
				<div class="column">Ch3<br><div class="v-box"></div><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p></div>
			</div>

なるほど

bluma CSSでヘッダー&メニュー作成

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link rel="stylesheet" href="css/style.css">
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
	<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.1/css/all.css" integrity="sha384-vp86vTRFVJgpjF9jiIGPEEqYqlDwgyBgEF109VFjmqGmIY/Y4HV4d3Gp2irVfcrp" crossorigin="anonymous">
</head>
<body>
	<div id="app">

	<nav class="navbar" role="navigation" aria-label="main navigation">
  	<div class="navbar-brand">
	    <a class="navbar-item" href="/home" style="font-size:1.5em;font-weight:bold;">
	      <!-- <img src="https://bulma.io/images/bulma-logo.png" width="112" height="28"> -->
	      Speech Recognition Demo
	    </a>

	    <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="">
	      <span aria-hidden="true"></span>
	      <span aria-hidden="true"></span>
	      <span aria-hidden="true"></span>
	    </a>
	</div>

  	<div id="" class="navbar-menu">
    <!-- <div class="navbar-start">
      <a class="navbar-item">
        Home
      </a>
      <a class="navbar-item">
        Documentation
      </a>
    </div> -->

	    <div class="navbar-end">
	      <div class="navbar-item">
	      	<div class="navbar-item has-dropdown is-hoverable">
	        <a class="navbar-link">
	          Language
	        </a>

	        <div class="navbar-dropdown">
	          <a class="navbar-item">
	            English
	          </a>
	          <a class="navbar-item">
	            Chinese
	          </a>
	          <a class="navbar-item">
	            Japanase
	          </a>
	        </div>
	      </div>
	        <div class="buttons">
	          <a class="button is-light">
	            Logout
	          </a>
	        </div>
	      </div>
	    </div>
	  </div>
	</nav>

	<section class="main-content columns is-fullheight">
	<aside class="column is-3 is-narrow-mobile is-fullheight section is-hidden-mobile">
    <p class="menu-label is-hidden-touch">MENU</p>
    <ul class="menu-list">
      <li>
        <a href="/home" class="">
          <span class="icon"><i class="fa fa-home"></i></span> Home
        </a>
      </li>
      <li>
        <a href="#" class="">
          <span class="icon"><i class="fa fa-table"></i></span> Channel
        </a>

        <ul>
          <li>
            <a href="#">
              <span class="icon is-small"><i class="fa fa-link"></i></span> Ch1
            </a>
          </li>
          <li>
            <a href="#">
              <span class="icon is-small"><i class="fa fa-link"></i></span> Ch2
            </a>
          </li>
          <li>
            <a href="#">
              <span class="icon is-small"><i class="fa fa-link"></i></span> Ch3
            </a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#" class="">
          <span class="icon"><i class="fa fa-id-card"></i></span> MyPage
        </a>
      </li>
      <li>
        <a href="#" class="">
          <span class="icon"><i class="fa fa-file-alt"></i></span> Document
        </a>
      </li>
      <li>
        <a href="#" class="">
          <span class="icon"><i class="fa fa-comments"></i></span> Chat room
        </a>
      </li>
    </ul>
  </aside>
	

	<div class="container column is-9">
		<div class="section">
			<div class="card">
				<div class="card-header"><p class="card-header-title">Header</p></div>
				<div class="card-content"><div class="content">Content</div></div>
			</div>
			<br>

			<div class="card">
				<div class="card-header"><p class="card-header-title">Header</p></div>
				<div class="card-content"><div class="content">Content</div></div>
			</div>
			<br>

			<div class="columns">
				<div class="column">Column1</div>
				<div class="column">Column2</div>
				<div class="column">Column3</div>
			</div>
		</div>

	</div>

	</section>
	<footer class="footer is-hidden">
		<div class="container">
			<div class="content has-text-centered">
				<p>Hello</p>
			</div>
		</div>
	</footer>
	</div>
	<script src="bundle.js"></script>
</body>
</html>

うん、いい感じです

bluma CSSでLoginページを作成

<div class="hero is-fullheight is-primary">
		<div class="hero-body">
			<div class="container has-text-centered">
				<div class="column is-8 is-offset-2">
					<h3 class="title has-text-white">Speech Recognition Demo</h3>
					<hr class="login-hr">
					<p class="subtitle has-text-white">Login</p>
					<div class="box">
						<!-- <div class="box">
							<img src="img/login.png">
						</div> -->
						<div class="title has-text-grey is-5">Please enter your email and password.</div>
						<form>
							<div class="field">
								<div class="control">
									<input class="input is-large" type="email" placeholder="Email" autofocus="">
								</div>
							</div>
							<div class="field">
								<div class="control">
									<input class="input is-large" type="password" placeholder="Password">
								</div>
							</div>
							<button class="button is-block is-danger is-large is-fullwidth">Login</button>
						</form>
						<br>
						<p class="has-text-grey">
							<a href="">Sign Up</a> &nbsp;&nbsp;
							<a href="">Forgot Password</a> &nbsp;&nbsp;
							<a href="">Need Help?</a>
						</p>
					</div>
				</div>

			</div>
		</div>
	</div>

bootstrapにはない体験ができますね。

Webpackでsassとtypescriptの環境を作る

package.json

{
  "name": "front",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --mode development --env development",
    "dev": "webpack-dev-server --mode development --env development",
    "build": "webpack --mode production"
  },
  "keywords": [],
  "author": "hpscript",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.12.13",
    "@babel/preset-env": "^7.12.13",
    "@babel/preset-react": "^7.12.13",
    "babel-loader": "^8.2.2",
    "css-loader": "^5.0.2",
    "mini-css-extract-plugin": "^1.3.6",
    "node-sass": "^5.0.0",
    "optimize-css-assets-webpack-plugin": "^5.0.4",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "sass-loader": "^11.0.1",
    "style-loader": "^2.0.0",
    "ts-loader": "^9.2.6",
    "typescript": "^4.4.3",
    "webpack": "^5.53.0",
    "webpack-cli": "^4.8.0",
    "webpack-dev-server": "^4.2.1"
  },
  "description": ""
}

webpack.config.js

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
	entry: {
		anyname: `./src/scss/style.scss`,
		bundle: './src/app.ts'
	},
	output: {
		path: path.join(__dirname,'dist'),
		filename: '[name].js'
	},
	resolve: {
		extensions:['.ts','.js']
	},
	devServer: {
		host: '192.168.34.10',
        port: '8000',
        static: "./dist",
        open: true
	},
	module: {
		rules: [
			{
				test:/\.ts$/,use:'ts-loader'
			},
			{
                test: /\.scss$/,
                use: [
                    { loader: MiniCssExtractPlugin.loader },
                    { loader: 'css-loader' },
                    { loader: 'sass-loader' },
                ],
            }
		]
	},
	plugins: [
        new MiniCssExtractPlugin({ filename: 'css/style.css'}),
    ],
    optimization: {
        minimizer: [new OptimizeCSSAssetsPlugin({})],
    },
}

tsconfig.json

環境構築まではOK^^