minikubeでcreate deployment

$ sudo kubectl get nodes
$ sudo kubectl describe nodes ubuntu-bionic
$ sudo kubectl proxy
Starting to serve on 127.0.0.1:8001

※kubectlはクラスタのマスターノード上で実行される

$ sudo kubectl get pods -o wide
No resources found in default namespace.
$ sudo kubectl get pods -o json
{
“apiVersion”: “v1”,
“items”: [],
“kind”: “List”,
“metadata”: {
“resourceVersion”: “”,
“selfLink”: “”
}
}

### hello-minikube
// pod, deployment作成
$ kubectl run hello-minikube –image=k8s.gcr.io/echoserver:1.4 –port=8080
// get deployment
$ sudo kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
hello-minikube 0/1 1 0 2m
// serviceを使う
$ sudo kubectl expose deployment hello-minikube –type=NodePort
service/hello-minikube exposed
$ sudo minikube service hello-minikube –url
$ curl http://192.168.33.10:30835
CLIENT VALUES:
client_address=172.17.0.1
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://192.168.33.10:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 – lua: 10001

HEADERS RECEIVED:
accept=*/*
host=192.168.33.10:30835
user-agent=curl/7.58.0
BODY:
-no body in request-v

### hello-node
$ sudo kubectl create deployment hello-node –image=gcr.io/hello-minikube-zero-install/hello-node

$ sudo kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
hello-minikube 1/1 1 1 38m
hello-node 1/1 1 1 21m

$ sudo kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-minikube-75cb6dd856-8rxx7 1/1 Running 0 38m
hello-node-7676b5fb8d-hdj6d 1/1 Running 0 21m

$ kubectl expose deployment hello-node –type=LoadBalancer –port=8080
$ sudo kubectl get services
$ curl http://192.168.33.10:32720
Hello World!

kubectl createでDockerコンテナを使用してpodを作成する
Deploymentを作成するとDeployment、replicaset, Podが作られる

k8sのアーキテクチャ

マスターコンポーネントでnodeを制御している
コンテナはnodeのpodの中で実行される
minikubeではマスターとウォーカーは同じサーバだが、k8sでは別サーバ

ロードバランサの役割もk8sでやってしまうイメージか。
create deploymentでGCPからimageをpullしているけど、実務上ではDockerfileでコンテナの仕様を書いていくと思うんだが、その場合のnode、podはどうやって作成して関連付けていくのか良く解らんな。サンプルじゃなくて、実際にアプリを作らないときついか?

18.04(bionic)でminikube🐳

$ uname -a
Linux ubuntu-bionic 4.15.0-91-generic #92-Ubuntu SMP Fri Feb 28 11:09:48 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ git –version
git version 2.17.1

### kubectl install
$ sudo snap install kubectl –classic
$ kubectl version
Client Version: version.Info{Major:”1″, Minor:”17″, GitVersion:”v1.17.3″, GitCommit:”06ad960bfd03b39c8310aaf92d1e7c12ce618213″, GitTreeState:”clean”, BuildDate:”2020-02-12T13:43:46Z”, GoVersion:”go1.13.7″, Compiler:”gc”, Platform:”linux/amd64″}

### Docker install
$ sudo apt-get update
$ sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add –
$ sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable”
$ sudo apt-get update
$ sudo apt-get install -y docker-ce docker-ce-cli containerd.io
$ sudo docker –version
Docker version 19.03.8, build afacb8b7f0

### docker-compose
$ sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose –version
docker-compose version 1.21.2, build a133471

### minikube
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ chmod +x minikube
$ sudo cp minikube /usr/local/bin
$ sudo minikube start –vm-driver=none
$ sudo minikube start –vm-driver=none
$ sudo minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
$ sudo kubectl get nodes
NAME STATUS ROLES AGE VERSION
ubuntu-bionic Ready master 16m v1.17.3

なんか良く解らないがminikubeが動いているように見える🐳
nodeがminikubeでなく、ubuntu-bionicになってるけど、合ってるのだろうか?

ubuntu14.04(trusty)でminikubeを起動しようと思ったら

ubuntuでkubernetesを学びたい🐳
docker, docker-composeはインストール済

$ uname -a
Linux vagrant-ubuntu-trusty-64 4.4.0-148-generic #174~14.04.1-Ubuntu SMP Thu May 9 08:17:37 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
$ docker –version
Docker version 18.06.3-ce, build d7080c1

1. kubectlインストール
2. Minikubeインストール

### kubectlのインストール
k8s公式を参考にする
install-kubectl
$ sudo apt-get update && sudo apt-get install -y apt-transport-https
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add –
$ echo “deb https://apt.kubernetes.io/ kubernetes-xenial main” | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
$ sudo apt-get update
$ sudo apt-get install -y kubectl
$ kubectl version
Client Version: version.Info{Major:”1″, Minor:”17″, GitVersion:”v1.17.4″, GitCommit:”8d8aa39598534325ad77120c120a22b3a990b5ea”, GitTreeState:”clean”, BuildDate:”2020-03-12T21:03:42Z”, GoVersion:”go1.13.8″, Compiler:”gc”, Platform:”linux/amd64″}

### minikubeインストール
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ sudo chmod +x minikube
$ sudo cp minikube /usr/local/bin
$ sudo minikube start –vm-driver=none
* minikube v1.8.2 on Ubuntu 14.04 (vbox/amd64)
* Using the none driver based on user configuration

! ‘none’ driver reported an issue: exec: “systemctl”: executable file not found in $PATH
* Suggestion: Use a systemd based Linux distribution
* Documentation: https://minikube.sigs.k8s.io/docs/reference/drivers/none/

X none does not appear to be installed

あ、14.04は古いのか。サポートも終了しているみたいだし、18.04でやり直そう。。

$ vagrant ssh
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

System information as of Sat Mar 21 05:59:25 UTC 2020

System load: 0.01 Processes: 109
Usage of /: 12.3% of 9.63GB Users logged in: 0
Memory usage: 16% IP address for enp0s3: 10.0.2.15
Swap usage: 0% IP address for enp0s8: 192.168.33.10

0 packages can be updated.
0 updates are security updates.

kubernetes基礎

公式サイト: kubernetes
Kuberntes Github:kubernetes / kubernetes

– 実行環境に依存しない(AWS, GCP, オンプレ)
– Docker以外のコンテナも可
– 複数ホストにコンテナをデプロイ
– サーバ台数関係なく、コンピュータ資源を最適化して複数のapplicationを起動できる(コンテナのリソースアロケーション)
– 負荷に応じてapplicationごとに自動で数を増減できる(コンテナの負荷分散)
– サーバを入れ替えることなくapplicationのデプロイが可能

masterとよばれる親機とnodeとよばれる子機サーバを用意して、kubernetesをそれぞれインストールして通信設定
ECSやGKEなどkubernetesマネージドサービスがある

k8sの構成は以下の通り
Ingress(通信内容をServiceにプロキシする)
Service(複数のPodに対して単一IPアドレスを割り当てる機能) ロードバランサのように振る舞う。ClusterIP、NodePort, LoadBalancer, ExternalNameなど
Cluster
L Node(コンテナをデプロイするための物理サーバ) k8sを管理するデーモンはNode上で実行
L Pod(デプロイの最小単位) 
L コンテナ

MiniKube:ローカルのVM内にk8sクラスタ内のコンテナを操作するためのKubernetesMasterと単一ノードのk8sクラスタを構築する

まずはminikubeで理解していくってことか?

EC2(amazon linux2)上でDockerを使う

テスト用ですぐにterminateするため、EC2のスペックは最小限にします

### Launch instance
– Amazon Linux 2 AMI (HVM), SSD Volume Type
– type: t2.nano
– subnet: public
– Auto-assign Public IP: enable
– volume: GP2 8Gib
– Security Group: HTTP 0.0.0.0/0, SSH 0.0.0.0/0

### 前準備
$ ssh ec2-user@${public ip} -i ~/.ssh/${秘密鍵}.pem

// git install
$ sudo yum update
$ sudo yum -y install gcc curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker autoconf
// 省略

### EC2にDocker.ceインストール
// Extras Libraryを見てみる
$ amazon-linux-extras
20 docker=latest enabled \
[ =17.12.1 =18.03.1 =18.06.1 =18.09.9 =stable ]
$ amazon-linux-extras info docker
docker recommends docker # yum install docker

ありますね、extrasからインストールします。
$ sudo amazon-linux-extras install docker
$ docker –version
Docker version 18.09.9-ce, build 039a7df

### Docker-compose install
$ sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose –version
docker-compose version 1.21.2, build a133471

## docker構築
### docker-compose.yml & Dockerfile
-docker-composeの構成やimageはlocal環境(ubuntu)と同じにする
-> nginx:1.13.5-alpine, node:12.13.0-alpine&php:7.3-fpm-alpine, FROM mysql:5.7.19

$ docker-compose build
ERROR: Couldn’t connect to Docker daemon at http+docker://localhost – is it running?
あれ?
$ sudo docker-compose build
sudo: docker-compose: command not found
ん?

権限をec2-userに付与する
$ sudo usermod -a -G docker ec2-user
$ cat /etc/group |grep docker
docker:x:993:ec2-user

$ docker info
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
あれ?

$ sudo service docker start
$ sudo docker info

### build & up -d
$ docker-compose build
$ docker-compose up -d
$ docker-compose ps
Name Command State Ports
———————————————————————-
app-1 docker-php-entrypoint php-fpm Up 9000/tcp
db-1 docker-entrypoint.sh mysql … Exit 1
nginx-1 nginx -g daemon off; Up 0.0.0.0:80->80/tcp
ん?
$ docker logs db-1

EC2でもswapメモリを増設する
$ sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024
$ sudo /sbin/mkswap /var/swap.1
$ sudo /sbin/swapon /var/swap.1

$ docker-compose ps
Name Command State Ports
————————————————————————-
app-1 docker-php-entrypoint php-fpm Up 9000/tcp
db-1 docker-entrypoint.sh mysql … Up 0.0.0.0:3306->3306/tcp
nginx-1 nginx -g daemon off; Up 0.0.0.0:80->80/tcp

### 動作確認
$ docker exec -it app-1 sh
/var/www/html # ls
index.html index.php
$ docker exec -it nginx-1 sh
/ # cd /var/www/html
/var/www/html
$ docker exec -it db-1 bash
root@3e44157ee4fc:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.19 MySQL Community Server (GPL)

publicIPを叩く
http://**.***.***.***/
-> OK

なるほど、ローカルと全く一緒なので割と直ぐに環境構築ができます。
any application, anywhereが実感できる。
EC2の場合は冗長化が前提なので、mysqlのコンテナは必要なしでRDSに繋げるところが異なるか。vagrantが長かったせいか、商用環境にコンテナを使うのは違和感があったが、実際動かしてみると、Dockerでも別に差し支えないように見える。

インフラに変更を加えなければ、デプロイはCodeDeployで対応できそうだが、パッケージ等を入れるにしても、Dockerfileを更新するだけってのは確かに良いかも。
そして、デプロイやロードバランサまわり、オートスケーリングなどをkubernetesで管理するのね。

Laravel7.x : Expected status code 200 but received 302.

Circle CIでテスト

There was 1 failure:

1) Tests\Feature\ExampleTest::testBasicTest
Expected status code 200 but received 302.
Failed asserting that false is true.

/home/circleci/repo/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:185
/home/circleci/repo/tests/Feature/ExampleTest.php:19

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

リダイレクト処理で302になっている為。
tests/Feature/ExampleTest.php

    public function testBasicTest()
    {
        $response = $this->get('/');

        // $response->assertStatus(200);
        $response->assertStatus(302);
    }

-> SUCCESS

OK^^

Docker + Laravel7.2 + CircleCIで継続的インテグレーション

### Docker環境の構築
CircleCIを使うにあたって、Dockerで環境を構築する
– nginx:1.13.5-alpine、node:12.13.0-alpine + FROM php:7.3-fpm-alpin、mysql:5.7.19で作成
※docker-compose.yml, Dockerfileの記載は省略

$ sudo docker-compose build
$ sudo docker-compose up -d
$ sudo docker ps
$ sudo docker exec -it app-1 sh

$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar create-project –prefer-dist laravel/laravel app
$ php artisan –version
Laravel Framework 7.2.0

$ /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024
$ /sbin/mkswap /var/swap.1
$ /sbin/swapon /var/swap.1
$ vi composer.json

"require": {
        "php": "^7.2.5",
        "fideloper/proxy": "^4.2",
        "fruitcake/laravel-cors": "^1.0",
        "guzzlehttp/guzzle": "^6.3",
        "laravel/framework": "^7.0",
        "laravel/tinker": "^2.0",
        "laravel/ui" : "^2.0"
   },

$ php composer.phar update
$ php artisan ui vue –auth
$ php artisan migrate
$ npm install
$ npm run dev

$ sudo docker exec -it db-1 bash
$ mysql -u root -p
mysql> use mydb
mysql> show tables;
+—————–+
| Tables_in_mydb |
+—————–+
| failed_jobs |
| migrations |
| password_resets |
| users |
+—————–+
4 rows in set (0.07 sec)

// 動作確認、日本語のレコードが問題なく入るか
http://192.168.33.10/login
http://192.168.33.10/register
mysql> select * from users;

### Circle CI
– CircleCIでLaravelのMySQLを使ったテストを実行する
Experimental CircleCI images for MySQL
> The following is the customizations CircleCI applies in a Dockerfile:

FROM mysql:latest
ENV MYSQL_ALLOW_EMPTY_PASSWORD=true \
    MYSQL_DATABASE=circle_test \
    MYSQL_HOST=127.0.0.1 \
    MYSQL_ROOT_HOST=% \
    MYSQL_USER=root

config/database.php

'connections' => [

        'circle_test' => [
            'driver' => 'mysql',
            'host' => '127.0.0.1',
            'port' => '3306',
            'database' => 'circle_test',
            'username' => 'root',
            'password' => '',
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'engine' => null,
        ], 

docker imageを選択する
-> laravelの環境に合わせてcircleci/php:7.3.9-apache-node-browsersにする
https://circleci.com/docs/ja/2.0/docker-image-tags.json

.circleci/config.yml

version: 2
jobs:
  build:
    docker:
      - image: circleci/php:7.3.9-apache-node-browsers
      - image: circleci/mysql:5.7

    environment:
      - APP_DEBUG: true
      - APP_ENV: testing
      - APP_KEY: base64:62bhVUIMcTWoVIzZm**************
      - DB_CONNECTION: circle_test
      - MYSQL_ALLOW_EMPTY_PASSWORD: true

    working_directory: ~/repo

    steps:
      - checkout

      - run: sudo docker-php-ext-install pdo_mysql

      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "composer.json" }}
          - v1-dependencies-

      - run: composer install -n --prefer-dist

      - save_cache:
          paths:
            - ./vendor
          key: v1-dependencies-{{ checksum "composer.json" }}

      - run: php artisan migrate
      - run: php artisan db:seed

      - run: php ./vendor/bin/phpunit

$ git add .
$ git config –global core.autoCRLF false
$ git commit -m “circleci”
$ git remote add origin https://github.com/hoge/circleci.git
$ git push -u origin master

repositoryをprivateにして再度 git push。
-> success
private repoでもできるのね。

というか、CircleCI自体がDockerのimageを使っているだけで、別にプロジェクト自体はDocker環境だけでなく、Vagrantでも行けそうですね。

Docker+laravel7.xでrequire laravel/uiでInstallation failed, reverting ./composer.json to its original content.

Dockerのphp:7.3-fpm-alpineで、composer require laravel/uiを入れようとすると「Installation failed, reverting ./composer.json to its original content.」のエラーになる。

$ php composer.phar require laravel/ui:^2.0
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing laravel/ui (v2.0.1): Downloading (100%)

Installation failed, reverting ./composer.json to its original content.


Warning: proc_open(): fork failed - Out of memory in phar:///var/www/html/composer.phar/vendor/symfony/console/Application.php on line 952

  [ErrorException]
  proc_open(): fork failed - Out of memory

最初、fork failed – Out of memoryのエラーが出ているので、swapメモリを増やしたが、結果は同じ。
$ /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024
$ /sbin/mkswap /var/swap.1
$ /sbin/swapon /var/swap.1

色々調べたがLaravel7.x系は記事が少なく、原因はわからず。とりあえずcomposer.jsonに直接書いてupdateしてみることに。
$ vi composer.json

"require": {
        "php": "^7.2.5",
        "fideloper/proxy": "^4.2",
        "fruitcake/laravel-cors": "^1.0",
        "guzzlehttp/guzzle": "^6.3",
        "laravel/framework": "^7.0",
        "laravel/tinker": "^2.0",
        "laravel/ui" : "^2.0"
   },
$ php composer.phar update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing laravel/ui (v2.0.1): Downloading (100%)
Writing lock file
Generating optimized autoload files
// 省略

上手くいきました。何故だろう???
Docker上でcomposer requireするときはcomposer.jsonに書かないと駄目なのか?理由が良く解らない。

Laravel6.2 → Laravel 7.xへのアップグレード手順

公式ドキュメント: Upgrade Guide

Update your laravel/framework dependency to ^7.0 in your composer.json file. In addition, update your nunomaduro/collision dependency to ^4.1, phpunit/phpunit dependency to ^8.5, laravel/tinker dependency to ^2.0, and facade/ignition to ^2.0.

composer.json

//省略

"laravel/framework": "^7.0",
"nunomaduro/collision": "^4.1",
"phpunit/phpunit": "^8.5"
"laravel/tinker": "^2.0",
"facade/ignition": "^2.0",
"laravel/ui": "^2.0",

// 省略

App/Exceptions/Handler
-> composer.updateする前に変更しないとエラーになる

use Throwable;

// public function report(Exception $exception)
public function report(Throwable $exception)

// public function render($request, Exception $exception)
public function render($request, Throwable $exception) 

$ php composer.phar update
$ php artisan –version
Laravel Framework 7.2.1

## 主要変更点
– Symfony 5 関連のアップグレード
— App\Exceptions\Handlerクラスのreportとrender
— コンフィグファイルのsessionのoptionのデフォルト値の変更
– Authenticationー認証
— laravel/uiを~2.0にする必要
– Date Serializationー日付のシリアライズ化
— 2019-12-02 20:01:00は7系から2019-12-02T20:01:00.283041Zに更新
– $model->getOriginal()メソードはキャストされたモデルを使用

## その他変更点
– PHPのバージョン 7.2.5以上
– Blade::componentメソードをBlade::aliasComponentに変更
– Blade Components & “Blade X”
– “factory types”機能を削除
– addHiddenとaddVisible削除
– bootingとbootedをEloquentに追加
– resolveRouteBindingメソードは$fieldパラメータ使用
– Illuminate\Auth\Passwords\TokenRepositoryInterfaceにrecentlyCreatedTokenを使用
– queue:workコマンドのフラグ–daemonが削除
– Illuminate\Http\Resources\Json\Resourceは削除
– array セッションドライバのデータはカレントリクエストに持続的にアクセス
– TestResponseクラスのassertSee アサーションは自動的にエスケープ
– differentルールはリクエストに特定のパラメータが足りない場合に通らない

## 各変更点の確認
– Authentication
laravel/ui 2.0で異常なし

– コンフィグファイルのsessionのoptionのデフォルト値の変更
config/session.php

// 'secure' => env('SESSION_SECURE_COOKIE', false),
'secure' => env('SESSION_SECURE_COOKIE', null),

// 'same_site' => null,
'same_site' => 'lax',

– Date Serialization
一部データをJasonで送って、blade側でdateのデータ(created_at)をmomentでMM/DD HH:mmに変換しているが、挙動確認したところ影響はない。

– $model->getOriginal()
画像の保存処理で、$file->getClientOriginalName();としており、似ているため念の為確認したが、やはり問題なし

– Mail Configuration File Changes
laravel7.2をcreateして一応違いを確認しておく。
6系だとconfig/service.phpに書かれていたsmtp周りがconfig/mail.phpに纏められています。確かに、なんでservice.phpに?って思っていたので、これは良い改良です。

'mailers' => [
        'smtp' => [
            'transport' => 'smtp',
            'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
            'port' => env('MAIL_PORT', 587),
            'encryption' => env('MAIL_ENCRYPTION', 'tls'),
            'username' => env('MAIL_USERNAME'),
            'password' => env('MAIL_PASSWORD'),
        ],

        'ses' => [
            'transport' => 'ses',
        ],

        'sendmail' => [
            'transport' => 'sendmail',
            'path' => '/usr/sbin/sendmail -bs',
        ],

        'log' => [
            'transport' => 'log',
            'channel' => env('MAIL_LOG_CHANNEL'),
        ],

        'array' => [
            'transport' => 'array',
        ],
    ],

しかし、まさかもうLaravel6.x系が古くなるとは思わなかった。。

GitHub Issuesの書き方

公式ドキュメント:
Mastering Issues

公式を読むと、Milestones, Labels, Assignees, Notifications, mentions, References, Search, Overviews, Reportsなどの機能がある。

Github Markdown:Mastering Markdown

– 一つのissueに一つの事柄
– 画像はドラッグ&ドロップで貼り付けられる

書き方
– 概要、作業手順、チェック項目は出来るだけ細かく書く
– ブランチ名にissueの番号を使う
— feature${issueNumber}

$ git branch feature${id}
$ git checkout feature${id}
$ git branch

pull requestをmergeしたらissueはcloseする。