gitlab tips

### Services: コンテナイメージを複数扱う
servicesというキーワードを用いると、ベースイメージと接続可能なコンテナを定義できる

servies:
  - postgres:latest
variables:
  POSTGRES_DB: custom_db
  POSTGRES_USER: ucstom_user
  POSTGRES_PASSWORD: custom_password

### Anchors

test1:
  stage: test
  image: python:latest
  before_script:
    - pipenv install --dev --system
  script:
    - pytest test1

test2:
  state: test
  image: python:latest
  before_script:
    - pipenv install --dev --system
  script:
    - pytest test2
.test_template: &test_definition
  state: test
  image: python:latest
  before_script:
    - pipenv install --dev --system

test1:
  <<: *test_definition
  script:
    - pytest test1

test2:
  <<: *test_definition
  script:
    - pytest test2  

### 用意されているGitlab変数

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
  script:
    - docker build --pull -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
  only:
    - tags

### only and except
tagがpushされた時のみ
only:
– tags
ブランチがpushされた時は実行しない
except:
– master

あれ、Dockerfileではなく、gitlab.ymlにimageを書くの?

gitlab-ci.yml練習

stages:
  - prepare
  - echo

prepare-job:
  stage: prepare
  script:
    - echo "Prepare bofore echo"

echo-job:
  stage: echo
  script: 
    - echo "Ahoy! This is Gitlab CI/CD!"

stages:
  - dev
  - stg

dev-job:
  stage: dev
  script:
    - echo "Hello, $GITLAB_USER_LOGIN!"
    - echo "This is $CI_COMMIT_BRANCH branch."
    - sleep 5

stg-job:
  stage: stg
  script:
    - echo "hello world!"

$GITLAB_USER_LOGIN, $CI_COMMIT_BRANCH branchは予め用意されている模様

### Docker

default:
  image: ruby:2.7.2

stages:
  - stg

hello-job:
  stage: stg
  script:
    - ruby -v

### artifact

stages:
  - dev

generate-file:
  stage: dev
  artifacts:
    paths:
      - hoge.txt
  script:
    - echo hoge > hoge.txt

なるほど、なんか色々できそうなことはわかった

GitLab Container Registryを使おう

registoryにログインします
$ sudo docker login registry.gitlab.com
Login Succeeded

Dockerfile

FROM alpine:latest

### build
$ sudo docker build -t registry.gitlab.com/hpscript/docker .
$ sudo docker images;
registry.gitlab.com/hpscript/docker latest 9c842ac49a39 41 hours ago 5.57MB
$ sudo docker push registry.gitlab.com/hpscript/docker

なるほどー、なんか勉強になるな

[Docker Hub] イメージを登録する

1. リポジトリを作成する
ddddocker/myexample

2. Dockerイメージ名を調整する
$ sudo docker tag myphpimage ddddocker/myexample:v1

3. リポジトリログイン
$ sudo docker login

4. イメージ登録
$ sudo docker push ddddocker/myexample:v1

なるほど、なんとなく基礎はわかってきた。
あとはdockerfileのベストプラクティスとデプロイCI/CDのところか...

[Docker] イメージの保存と読み込み

– 作成したイメージをファイル化すると、別のコンピュータに持っていくことができる。
– ファイル化にはdocker saveを使う。
– ファイルから取り出すには docker loadを使う。

### docker saveでイメージからファイル化
$ sudo docker save -o saved.tar myphpimage
$ ls -al saved.tar
-rw——- 1 root root 262609920 Mar 24 07:19 saved.tar

内容確認
$ sudo tar tvf saved.tar

### docker loadする
$ sudo docker image rm myphpimage
$ sudo docker load -i saved.tar
$ sudo docker image ls
$ sudo docker stop myphp02
$ sudo docker rm myphp02


export/importによるファイル化
L コンテナ情報が失われるためあまり使用しない

なるほど、Docker hubなどを使わなくても、tarファイルに出来るんだね
中々勉強になるわ…

[Docker] コマンドの実行

コマンドの実行系統の命令は「RUN」「CMDとENTRYPOINT」の2種類ある
前者はイメージ作成時、後者はコマンドの実行時

### RUN
RUNコマンドはdocker buildするタイミング
(1)シェル形式
/bin/sh -cを経由してコマンドが実行
RUN ${コマンド} ${引数} …

(2)exec形式
実行したいコマンドや引数を[]を囲んで記述
RUN [“コマンド”, “引数”, …]

RUNコマンドごとにレイヤーが増えるので、一つのコマンドで実現できる様にする
RUN コマンド1 && コマンド2 && コマンド3

ONBUILD COPY コピー元 コピー先

### CMDとENTRY POINT
コンテナを起動したときのタイミングでコンテナの中で実行するコマンドを指定する
(1)ENTRY POINT: コマンドの指定を強要する。イメージの利用者はこの設定を変更することはできない。
docker runの最後に指定するコマンドは、ENTRYPOINTで指定したコマンドへの引数となる

(2)CMD
docker runの際に指定する最後のコマンドのデフォルト値を変更

殆どの場合、CMDが使われる
イメージが通信しようとするポート番号はEXPOSEで指定する

### HTTPDのDockerfile
https://github.com/docker-library/httpd/blob/master/2.4/Dockerfile

phpimage/index.php

<body>
	Your IP <?php echo $_SERVER['REMOTE_ADDR']; ?>。
</body>

Dockerfile

FROM debian
EXPOSE 80
RUN apt update \
&& apt install -y apache2 php libapache2-mod-php \
&& apt clean \
&& rm -rf /var/lib/apt/lists/* \
&& rm /var/www/html/index.html
COPY index.php /var/www/html
CMD /usr/sbin/apachectl -DFOREGROUND

apt clean, rm -rf /var/lib/apt/lists/* でパッケージを削除する。常套句。
中間ファイルを削除することで、Dockerイメージのサイズを小さくできる
CMD /usr/sbin/apachectl -DFOREGROUND でapacheをフォアグラウンドで実行する

$ sudo docker build . -t myphpimage
$ sudo docker images;
REPOSITORY TAG IMAGE ID CREATED SIZE
myphpimage latest 5c4aa75b77ce 4 minutes ago 254MB

– コンテナを動かす
$ sudo docker run -dit –name myphp -p 8080:80 myphpimage

キャッシュを活用するとビルドを高速化できる
キャッシュを使わない場合は、docker build . -t myphpimage –no-cache とする

なるほど、Dockerfileの作成は練習が必要だな…

[Docker] fileのbuild

Dockerfile

FROM httpd
COPY index.html /usr/local/apache2/htdocs/

1行目はFROM命令
「#」はコメント
行を跨ぐときは末尾に「¥」を記述
「${環境変数}」は環境変数

index.html

<body>
	<h1>Docker Test</h1>
</body>

### イメージをビルド
$ sudo docker build -t myimage01 .
$ sudo docker images;
REPOSITORY TAG IMAGE ID CREATED SIZE
myimage01 latest b2397acb1a5a 43 seconds ago 144MB
$ sudo docker history myimage01;
IMAGE CREATED CREATED BY SIZE COMMENT
b2397acb1a5a About a minute ago /bin/sh -c #(nop) COPY file:752610804eacad0e… 213B

$ sudo docker run -dit –name webcontent_docker -p 8080:80 myimage01
7528440013bfa467f5e06d4f4a0b3eec0182ae5bb433d6045ee52611119f2b7c

http://192.168.56.10:8080/

なるほどー

### Dockerfileのコマンド
FROM
ベースイメージを指定する
ADD
イメージにファイルやフォルダを追加する。Dockerfileを置いたディレクトリ外のリモートファイルも指定できる。圧縮ファイルを指定したときは自動的に展開される。
COPY
イメージにファイルやフォルダを追加する。Dockerfileを置いたディレクトリ内のファイルしか指定できない。圧縮ファイルを指定したときは、圧縮ファイルのままコピーされる。
RUN
イメージをビルドするときにコマンドを実行する。
CMD
コンテナを起動するときに実行する既定のコマンド(docker createやdocker runで実行するコマンドを省略したとき)を指定する
ENTRYPOINT
イメージを実行するとき(docker createやdocker runするとき)のコマンドを強要する
ONBUILD
ビルド完了したときに任意の命令を実行する
EXPOSE
通信を想定するポートをイメージの利用者に伝える
ONBUILD
ビルドが完了したときに任意の命令を実行する
EXPOSE
通信を想定するポートをイメージの利用者に伝える
VOLUME
永続データが保存される場所をイメージの利用者に伝える
ENV
環境変数を定義する
WORKDIR
RUN, CMD, ENTRYPOINT, ADD, COPYの際の作業ディレクトリを指定する
SHELL
ビルド時のシェルを指定する
LABEL
名前やバージョン番号、制作者情報などを設定する
USER
RUN、CMD、ENTRYPOINTで指定するコマンドを実行するユーザやグループを設定する(USERを指定しない場合はroot)
ARG
docker buildする際に指定できる引数を宣言する
STOPSIGNAL
docker stopする際に、コンテナで実行しているプログラムに対して送信するシグナルを変更する(規定は)
HEALTHCHECK
コンテナの死活確認をするヘルスチェックの方法をカスタマイズする

[CakePHP4.x] 3系との違いを考える

$ php composer.phar create-project –prefer-dist cakephp/app:4.* blog
$ bin/cake server -H 192.168.56.10 -p 8000
$ bin/cake migrations migrate

migrations migrate
migrations migrate -t migrationID
migrations rollback
migrations rollback -t migrationID
migrations status

PostsTable.php

    public function validationDefault(Validator $validator): Validator
    {
        $validator
            ->integer('id')
            ->allowEmptyString('id', null, 'create');

        $validator
            ->scalar('title')
            ->maxLength('title', 150, '150文字以上で入力してください。')
            ->minLength('title', 5, '5文字以上で入力してください。')
            ->notEmptyString('title', 'タイトルは必ず入力してください');

        $validator
            ->scalar('description')
            ->maxLength('description', 255, '150文字以上で入力してください。')
            ->allowEmptyString('description');

        $validator
            ->scalar('body')
            ->allowEmptyString('body');

        $validator
            ->boolean('published')
            ->notEmptyString('published');

        return $validator;
    }

OK、続いて、デプロイ周りか…

[CakePHP] 3.xの復習

– データベースの作成から(mysql)
create database cake3
use cake3

create table posts (
id int unsigned auto_increment primary key,
title varchar(255),
body text,
created datetime default null,
modified datetime default null
);
insert into posts (title, body, created) values
(‘title 1’, ‘body 1’, now()),
(‘title 2’, ‘body 2’, now()),
(‘title 3’, ‘body 3’, now());
select * from posts;

– cakephpのインストール
composerでインストールする
$ php composer.phar create-project –prefer-dist cakephp/app:3.* myapp

### ディレクトリ構成の変更
– srcフォルダ新設
– webrootがWebブラウザからアクセスしたときに見るフォルダ

### 2系と3系の違い
1
ディレクトリ構成の変更
app, lib, plugins, vendors
bin, config, plugins, src, tests, tmp, vendor, webroot
-srcの中に、controller, model viewが入る
-webrootにpublicなファイルを配置
2
intl拡張モジュール
不要
必要
php-intlインストール
2
ビルトインサーバー
なし
bin/cake server -H 192.168.56.10 -p 8000

3
データベースの設定
app/Config/database.php
config/app.php

4
タイムゾーンの設定
app/Config/core.php
config/app.php

5
MVCファイルの作成
手動
bin/cake bake all ${app}

6
Modelファイル
app/Model/Post.php
src/Model/Table/PostsTable.php

7
Modelの書き方
class Post extends AppModel{
}
name space App\Model\Table
use Cake\ORM\Table;
class PostsTable extends Table{
}
名前空間を定義
ORM, Validation等を使用
Classの中にinitializeで初期化
8
Viewファイル
app/View/Posts/index.ctp
src/Template/Posts/index.ctp
titleなどはviewの中に記載
elementを追加できる
9
Controllerファイル
app/Controller/PostsController.php
src/Controller/PostsController.php

10
Controllerの書き方

namespace App\Controller;
class PostsController extends AppController { 
}
レコードの作成は$this->Posts->newEntity();と書く
11
Controllerでのfindの書き方
$this->Post->find(‘all’, $params);
$this->Post->find(‘all’)->order([‘title’=>’DESC’]);
繋げて条件を指定できる
12
Routing
app/Config/routes.php
config/routes.php

13
Template
app/View/Layouts/default.ctp
src/Template/Layout/default.ctp
controllerに$this->viewBuilder()->layout(‘my_layout‘);で独自テンプレートを表示できる
14
Validation
modelでarrayで定義
modelでValidationDefaultで定義

うーむ、これ3系と4系の違いもやらんといけんのか…

[CakePHP] 2.xの復習

公式サイト
https://cakephp.org/jp
ドキュメント
https://book.cakephp.org/4/ja/index.html

PHP/MySQL/HTMLCSSJS

– 覚えておいた方が良い用語
MVC -> Model, View, Controller
CoC: Convention over Configuration

CakePHP 2.xをインストールしようと思ったが…
$ git clone -b 2.x git://github.com/cakephp/cakephp.git
Cloning into ‘cakephp’…
fatal: remote error:

composerで入れるか…
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar create-project –prefer-dist ‘cakephp/app:2.10.*’ myapp
Creating a “cakephp/app:2.10.*” project at “./myapp”

[InvalidArgumentException]
Could not find package cakephp/app with version 2.10.*.

composerでももはや無理なので、githubから無理やり取得します
https://github.com/cakephp/cakephp/tree/2.10.22

ここまででそこそこ時間がかかってしまった…orz
$ cd cakephp-2.10.22

appを使う
controller, model, view

書き込み権限
$ sudo chown -R vagrant app/tmp/

create table posts(
id int not null auto_increment primary key,
title varchar(50),
body text,
created datetime default null,
modified datetime default null
);

insert into posts (title, body, created, modified) values
(‘title 1’, ‘body 1’, now(), now()),
(‘title 2’, ‘body 2’, now(), now()),
(‘title 3’, ‘body 3’, now(), now());

Model/Post.php

class Post extends AppModel {
	
}

Controller/PostsController.php

class PostsController extends AppController {

	public $helpers = array('Html', 'Form');

	public function index(){
		$params = array (
			'order' => 'modified desc',
			'limit' => 2
		);
		$this->set('posts', $this->Post->find('all', $params));
		$this->set('title', '記事一覧');
	}
}

/View/posts/index.ctp

<h2></h2>

<ul>
<?php foreach ($posts as $post) : ?>
<li>
<?php
// debug($post);
echo h($post['Post']['title']);
?>
</li>
<?php endforeach; ?>
</ul>

config/core.php

	Configure::write('debug', 0);

config/routes.php

	Router::connect('/', array('controller' => 'posts', 'action' => 'index'));

View/Layouts/default.ctp
-> templateが書かれている

URL -> /${controller}/${method}/

postscontroller.php

	public function view($id = null){
		$this->Post->id = $id;
		$this->set('post', $this->Post->read());
	}

/View/posts/view.ctp

<h2><?php echo h($post['Post']['title']); ?></h2>

<p><?php echo h($post['Post']['body']); ?></p>

index.ctp

echo $this->Html->link($post['Post']['title'], '/posts/view/'.$post['Post']['id']);

<h2>Add Post</h2>
<?php echo $this->Html->link('Add post', array('controller'=>'posts', 'action'=>'add')); ?>

add.ctp

<h2>Add post</h2>

<?php
echo $this->Form->create('Post');

echo $this->Form->input('title');
echo $this->Form->input('body', array('rows'=>3));
echo $this->Form->end('Save Post');
?>

エラーチェックはmodelにvalidationを書いていく
Mode/Post.php

class Post extends AppModel {
	public $validate = array(
		'title' => array(
			'rule' => 'notEmpty',
		),
		'body' => array(
			'rule' => 'notEmpty',
		)
	);
}

Posts/edit.ctp

<h2>Edit Post</h2>

<?php
echo $this->Form->create('Post'. array('action'=>'edit'));

echo $this->Form->input('title');
echo $this->Form->input('body', array('rows'=>3));
echo $this->Form->end('Save!');

2系はかなり古いか…
Cake自体があまり人気ないかも…