Docker環境構築(Rails)①

入門~インストールはこちら
devdevdev.hatenablog.com

DockerとDocker-Compose

Dockerはコンテナの管理
Dockerfileで色々管理

Docker-Composeは複数のコンテナの管理
docker-compose.ymlで色々管理
Docker-Composeで環境を作るコンテナの内容によってはDockerfileは不要

くらいに覚えておけば十分かと。

構築する環境

App(Ruby 2.5.1) - アプリケーションサーバ
MySQL 5.7.21 - DB
Nginx 1.13.10 - Webサーバー
phpMyAdmin - 何かと便利
Redis 3.2.11 - KVS



ファイル構成

- app/
- docker-compose.yml
- docker/
    - app/
        - Dockerfile
    - mysql/
        - conf.d/
            - custom.cnf
    - nginx/
        - app.conf

docker/配下のファイルの用意

App

Dockerfileを用意

FROM ruby:2.5.1

ENV APP_ROOT /var/www/app
WORKDIR $APP_ROOT
MySQL

Dockerfileは不要。
mysql/conf.d/custom.cnfを用意しましょう。

[client]
default-character-set=utf8

[mysqld]
character-set-server=utf8

[mysqld_safe]
timezone = UTC
Nginx

Dockerfileは不要
nginx/app.confを用意しましょう。

server {
    listen 80 default_server;
    index index.php index.html index.htm;
    root /var/www/app;
}
phpMyAdmin

Dockerfileも何もいりません。

Redis

Dockerfileも何もいりません。



docker-compose.ymlの作成

version: '2'
services:
  app:
    build:
      context: .
      dockerfile: ./docker/app/Dockerfile
    volumes:
      - ./app:/var/www/app
    ports:
      - 3000:3000
    depends_on:
      - mysql
      - redis
  mysql:
    image: mysql:5.7.21
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: app
    ports:
      - 3306:3306
    volumes:
      - ./docker/mysql:/etc/mysql/conf.d
  nginx:
    image: nginx:1.13.10
    ports:
      - 80:80
    volumes_from:
      - app
    volumes:
      - ./app:/var/www/app
      - ./docker/nginx:/etc/nginx/conf.d
    depends_on:
      - app
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=mysql
      - PMA_USER=root
      - PMA_PASSWORD=password
    links:
      - mysql
    ports:
       - 8080:80
  redis:
    image: redis:3.2.11
起動してみる
$ docker-compose up

・エラーが表示されない
http://localhost/にアクセスしてNginxの404が表示される
http://localhost:8080/にアクセスしてphpMyAdminが表示される
のが確認できれば完了。停止はControl + cで。
アプリケーションの用意は次回やります。



Trouble shooting
ERROR: for mysql  Cannot start service mysql: b'Mounts denied: ~

ファイルを作った場所によってはこんなエラーが出る場合があります。

f:id:devdevdev:20180404003130p:plain
右上のクジラアイコンをクリックして、「Preferences」

f:id:devdevdev:20180404003143p:plain
「File Sharing」でdocker-compose.ymlがある場所を追加しましょう。
終わったら「Apply & Restart」してしばらく待ちましょう。






Docker入門~インストール

そういえば書いてなかった気がする&人に説明するので、筆を取ることにしました。

入門

Dockerとは

コンテナ仮想化ツール
簡単に言うとPC上にWebサーバーとか、DBサーバーとかを一つにまとめた環境をポンと構築できるよってやつ。
Vagrantとかは1台の仮想マシンに1マシンになるので、WebサーバーとDBサーバーを立てようと思ったら2つ必要になるのが大きな違いかな。

Dockerを使うメリット

本番環境と同じ環境を簡単に用意できる。
なんならそのまま本番環境に使えるらしい。
起動とか処理が早い。
軽い。
コマンドを叩くだけで環境構築完了!

Docker用語

・イメージ:コンテナの元となるもの。EC2でいうAMI。Docker Hubというところにある。
・コンテナ:イメージを元に作られたもの。ここに各プロジェクト用の情報などが設定される。EC2でいうインスタンス



PC環境

Mac OSX High Sierraです。



インストール

Docker Store
から「Docker Community Edition for Mac」をダウンロードしましょう。
f:id:devdevdev:20180403212400p:plain
f:id:devdevdev:20180403212446p:plain

ダウンロードした「Docker.dmg」をダブルクリックして開きましょう。
書いてあるとおりにドラッグ&ドロップすれば完了!
f:id:devdevdev:20180403215505p:plain

設定

特にないけど。
Launch PadからでもなんでもDockerを起動。

f:id:devdevdev:20180403215718p:plain
「Next」

f:id:devdevdev:20180403215738p:plain
「OK」

f:id:devdevdev:20180403215833p:plain
Macのパスワードを入力して「OK」

f:id:devdevdev:20180403215912p:plain
こうなったら起動完了!




【Swift4】【Codable】 CodingKeys書くのだるいよね

とゆーわけで作りました。SwiftLint対応。

SOURCE_DIR="$PROJECT_DIR/Hoge/Models"
DEST_DIR="$PROJECT_DIR/Hoge/ModelExtensions"

find $DEST_DIR -name "*Ex.swift" -type f | while read FILE
do
    rm -f ${FILE}
done

find $SOURCE_DIR -name "*.swift" -type f | while read FILE
do
    NAME=$(basename ${FILE} | sed "s/.swift//g")
    DEST_FILE=$DEST_DIR"/"$NAME"Ex.swift"
    touch $DEST_FILE
    echo "extension $NAME {" >> "$DEST_FILE"
    echo "    enum CodingKeys: String, CodingKey {" >> "$DEST_FILE"

    while read line; do
	if ! echo $line | grep -q //; then
	if echo $line | grep -q let; then
            NAME=$(echo $line | sed -e "s/:.*$//g" -e "s/^.*let //g")
            SNAKED=$(echo $NAME | gsed -r -e 's/^([A-Z])/\L\1\E/' -e 's/([A-Z])/_\L\1\E/g')
            if [ $NAME = $SNAKED ]; then
	        echo "        case $NAME" >> "$DEST_FILE"
	    else
	        echo "        case $NAME = "'"'"$SNAKED"'"' >> "$DEST_FILE"
	    fi
        fi
        fi
    done < ${FILE}

    echo "    }" >> "$DEST_FILE"
    echo "}" >> "$DEST_FILE"
done





おひさしぶり

今に始まったことじゃないけど、ここ最近のフリーランスageについて思うこと

わたくし
.NET系はだいたい何でもできて
iOSObjective-cもSwiftもできて。なんならARCなしで書いてたし
AndroidJavaもKotlinもできて。なんなら2.3くらいから書いてたし
WebはC#PHPRubyもできて、フロントエンドも人並みにはできて
DBはSQLServerMySQLpostgreSQLできて
AWSもできて
Unityもできて
toCtoBも業務システムもカジュアルゲームもソシャゲも3Dゲームも作れて
大手メーカーのもの作ってたから全世界に出荷されてるし
某キャリアのスマホユーザーはだいたい俺が作ったの使ったことあるはずだし
上場企業に新卒で入って
10億規模の有名ゲームのチーフエンジニアやってたし
フリーランスもやってたし
ベンチャーのCTO兼Co-Founderやってたし
有名ベンチャーの開発責任者もやってたし
有名ベンチャーのアドバイザーもやってるし
いまだにちょこちょこCTOの話とかはもらうし
経営実務は完璧にこなせるし
たぶん総務部長とかできるくらいには総務詳しいし
労働基準法とか法令関連もめっちゃ勉強したし
何年間も年数千万以上は契約取れ続けるくらいには営業できるし
もうすぐ三期目終えられそうなくらいにはちゃんと会社続けられてるけど
採用とマネジメントだけは苦手だけど


それでも
やはりIoTかVRか仮想通貨かAIかVUIかに手を出さなきゃかなとか
React Nativeやろうかとか
Unreal Engineやろうかとか
PhysonとGoとRやらなきゃとか
スモールビジネスじゃなくてスタートアップの経営もやっといたほうがいいかなとか
資金調達ってしたことないからしてみたほうがいいかなとか
日本だけでやってたらやばいんじゃないかとか
ものすごいめっちゃ不安ですよ。まじで。



会社員に戻っても絶対年収1000万は切らない自信はあるけど、いつ仕事がなくなるか怖くて不安でたまらんのが経営。
会社員よりマシとかいってフリーランスになる人見るとある意味尊敬する。
有給はあるし、福利厚生はあるし、残業代は出るし、会社から金もらって勉強できるし、まじで最高の身分だと思いますよ。はい。
ちなみに経営者側から見ると元フリーランスとか元経営者はあまり採用したくない。
これは人によるかもだけど。ぼくでも相手によるけど。


【iOS,Swift3】Extension晒す〜番外編〜Propertiesの巻

表題の通りです。ご査収ください。

import Foundation

public protocol Properties {
    
    func properties() -> [String: Any?]
}

extension Properties {
    
    public func properties() -> [String: Any?] {
        var dic = [String: Any?]()
        Mirror(reflecting: self).superclassMirror?.children.forEach { (child) in
            if let key = child.label {
                dic[key] = child.value
            }
        }
        Mirror(reflecting: self).children.forEach { (child) in
            if let key = child.label {
                dic[key] = child.value
            }
        }
        return dic
    }
}

補足。こんな感じで使います。


internal class Hoge: Properties {

    internal var printProperties {
        properties().forEach { (key, value) in
            print("PropertyName: \(key) \nValue:\(String(describing: value))")
        }
    }
}





【iOS,Swift3】Extension晒す〜Date編〜

表題の通りです。ご査収ください。

import Foundation

extension Date {
    
    // MARK: - public property
    
    /// 週あたりの日数
    public var daysPerWeek: Int {
        get {
            return 7
        }
    }
    
    /// 月の初めの日
    public var firstDateOfMonth: Date {
        get {
            let calendar = NSCalendar.current
            var components = calendar.dateComponents([.year, .month, .day], from: self)
            components.day = 1;
            return calendar.date(from: components)!
        }
    }
    
    /// 月の週数
    public var numberOfWeeksForMonth: Int {
        get {
            let rangeOfWeeks = NSCalendar.current.range(of: Calendar.Component.weekOfMonth,
                                                        in: Calendar.Component.month,
                                                        for: firstDateOfMonth)
            return (rangeOfWeeks?.count)!
        }
    }
    
    /// 月の日数
    public var numberOfDaysForMonth: Int {
        get {
            let rangeOfDays = NSCalendar.current.range(of: Calendar.Component.day,
                                                       in: Calendar.Component.month,
                                                       for: firstDateOfMonth)
            return (rangeOfDays?.count)!
        }
    }

    // MARK: - public method

    /// toString()
    ///
    /// - Parameter format: フォーマット
    /// - Parameter calendarIdntifier: カレンダーIdentifier
    /// - Returns: 文字列
    public func toString(format: String, calendarIdentifier: Calendar.Identifier = .gregorian) -> String {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: calendarIdentifier)
        formatter.dateFormat = format
        return formatter.string(from: self)
    }
    
    /// fromString()
    ///
    /// - Parameters:
    ///   - string: 文字列
    ///   - format: フォーマット
    /// - Parameter calendarIdntifier: カレンダーIdentifier
    /// - Returns: Date
    public static func fromString(_ string: String, format: String, calendarIdentifier: Calendar.Identifier = .gregorian) -> Date? {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: calendarIdentifier)
        formatter.dateFormat = format
        return formatter.date(from: string)
    }
}





【iOS,Swift3】Extension晒す〜Array編〜

Androidエンジニアと見せかけて、
iOSエンジニア風を装って、
Unityエンジニアのふりして、
インフラエンジニアもちょっと名乗って、
当たり前のようにWebエンジニアとして仕事もするけど、
本業は未だに.NETエンジニアと思いたいけどたぶんもう無理で、
実際の身分はCEOとプレCTOとアプリ開発責任者の伊豆丸さんです。

表題の通りです。ご査収ください。


import Foundation

extension Array where Element: Hashable, Element: Equatable {
    
    public func diff(_ other: [Element]) -> [Element] {
        let all = self + other
        var counter: [Element: Int] = [:]
        all.forEach { counter[$0] = (counter[$0] ?? 0) + 1 }
        return all.filter { (counter[$0] ?? 0) == 1 }
    }
    
    public func subtracting(_ other: [Element]) -> [Element] {
        return self.flatMap { element in
            if (other.filter { $0 == element }).count == 0 {
                return element
            } else {
                return nil
            }
        }
    }
    
    public mutating func subtract(_ other: [Element]) {
        self = subtracting(other)
    }
}