nginxでgoを動かす

nginx上でgoを動かしてみたのでその手順をば。

nginxのインストール

今回の環境はローカルのmacで構築しています。

brew install nginx

でnginxを落とします

brewでダウンロードすると、/usr/local/etc/nginx にnginx.confが作成されます。
awsubuntu環境でapt-getした場合は /etc/nginx/nginx.confでした。(/etc/nginx/が一般的にnginx.confが置かれるディレクトリだと思います)

nginx.confを触ります

http {
    server {
         listen       8080;
         server_name  localhost;
         location / {
             proxy_pass http://127.0.0.1:9000;
         }
    }
}

軽く説明すると、そのまんまですが:8080で受けた / へのリクエストを:9000にリダイレクトしてます。 go + nginxでググるfastcgi_passを使っているのをよく見かけたのですが、シンプルにproxy_passを使えばよいかと思います。

nginx.confを修正したあとは

nginx -t

でnginx.confの記述が正しいかチェック

nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

こんな感じで出力されればokです

go

main.go

func main() {

   mux := http.NewServeMux()
   mux.HandleFunc("/", handler)
   s := &http.Server{
                Addr: ":9000",  
                Handler: mux,
    } 
   s.ListenAndServe()
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World")
}

シンプルに:9000にアクセスされればHello Worldを表示します。

動かす

// nginx 起動(:8080)
nginx 

nginxを打てばnginxが起動します

//go起動 (:9000)
go run main.go

これで、localhost:8080にリクエスト投げると、 nginxが9000にリダイレクトしてHello, Worldが出力されます

hashicorpのottoを触ってみた① ~ローカル環境構築

hashicorpのottoを触ってみたのでメモ

ottoは開発しているアプリケーションの内容を解釈して、自動的に開発環境を作成してくれるツールです。 例えば、goのプロジェクトを作成していた場合にはgoに必要な環境をinstallした状態の開発環境を作成します。 その流れを書いていきます。

ottoのインストール

ottoのインストールはhttps://ottoproject.io/downloads.html ここから適したバイナリファイルを落とすだけです。 落としたバイナリはそのままだと実行できないので /usr/local/bin 等に移動させるなどしてPATHを通しましょう。

ottoのappfileの作成

環境を作りたいプロジェクトのrootで

otto compile

これを実行すると

.otto
.ottoid

が作成されます。

.ottoの中を見ていくと .otto/appfile/ にAppfile.compiledというファイルがあります

その中身を開くと

{
    "File": {
        "ID": "1b090cd9-75e2-a4d1-22fa-658f945d2ae5",
        "Path": "/Users/hoge/_go/src/hoge/Appfile",
        "Source": "",
        "Application": {
            "Name": "hoge",
            "Type": "go",
            "Dependencies": null
        },
        "Project": {
            "Name": "hoge",
            "Infrastructure": "hoge"
        },
        "Infrastructure": [
            {
                "Name": "hoge",
                "Type": "aws",
                "Flavor": "simple",
                "Foundations": [
                    {
                        "Name": "consul",
                        "Config": null
                    }
                ]
            }
        ],
        "Customization": null,
        "Imports": null
    },
    "Vertices": [
        {
            "File": {
                "ID": "1b090cd9-75e2-a4d1-22fa-658f945d2ae5",
                "Path": "/Users/hoge/_go/src/hoge/Appfile",
                "Source": "",
                "Application": {
                    "Name": "hoge",
                    "Type": "go",
                    "Dependencies": null
                },
                "Project": {
                    "Name": "hoge",
                    "Infrastructure": "hoge"
                },
                "Infrastructure": [
                    {
                        "Name": "hoge",
                        "Type": "aws",
                        "Flavor": "simple",
                        "Foundations": [
                            {
                                "Name": "consul",
                                "Config": null
                            }
                        ]
                    }
                ],
                "Customization": null,
                "Imports": null
            },
            "Dir": "",
            "NameValue": "hoge"
        }
    ],
    "Edges": []
}

のようになっていて、otto compileした結果このプロジェクトはgoを使っていると判断してるみたいです。

その後

otto dev 

を叩くと、virtual boxに開発環境を作成してくれます。
実行内容を見てみると

==> default: [otto] Downloading Go 1.5...
==> default: [otto] Untarring Go...
==> default: [otto] Making GOPATH...

なにかしらgo の環境を整えているのが見られます。

otto dev ssh 

として構築した環境にsshでつなぎ

vagrant@precise64:/opt/gopath/src/hoge $ go version
go version go1.5 linux/amd64

goがインストールされてます。

このようにottoはプロジェクトの構成を解析してそれに適した環境を自動的に作成してくれます。

次回はAppfileや本番環境構築らへんについて書いていけたらなと思います。

circle.ymlの書き方

この記事は CircleCI Advent Calendar 2015 - Qiita の 8日目の記事です。
まだCircleCIを触って2週間のペーペーなので、基本的なところについてDove並みの優しさで書いていきたいと思います。
なのでベテランさんは通り過ぎてください。

※2017/11/21追記
この記事はCircleCI 1系の記事なので2系は書き方変わってます。 2.0の書き方は以下のブログを参考にしていただいたら分かりやすいかと思います。

blog.stormcat.io

circle.ymlの基礎

CircleCIの使い方として、まずプロジェクトのrootにcircle.ymlを置くことで、様々な設定を行うことができます。
circle.yml内に記述する主な項目として

  • machine:
  • checkout:
  • dependencies:
  • database:
  • test:
  • deployment:

の6つが用意されています。 用意はされていますが全て記述する必要はありません。
一個づつ説明していきます

machine

CircleCiのコンテナの設定を記述します。
よく使いそうなところで言えば

  • timezone:
  • hosts:
  • environment:
  • services:

といったところでしょうか。

machine:
    timezone: Asia/Tokyo
    
    hosts:   #/etc/hostsを書き換える
        dev.hogehoge.com: 127.0.0.1

    environment:
        DATABASE_URL: mysql://geho:@127.0.0.1:3306/hoge

    services:
        - cassandra
        

timezone,hosts,environmentはそのままの意味で、 servicesはCircleCiがデフォルトでインストールしていないdb serviceをインストールしたい時に記述します。

てかそもそも言語とかインストールしてないけど記述しなくていいのかという疑問があるかもしれません。
安心してください。入ってますよ。 https://circleci.com/docs/environment#languages
リンク先の内容が既にinstallされている設定です。 もし使ってる言語のversionがデフォルトと違うという場合は明示的に

machine:
    ruby:
        version: 2.1.4

というようにversionを指定する必要があります。

checkout

これはCircleCiを始める時にgitのプロジェクトを選択するだけで事足りてるので使ったことないのですが、sampleだとgitのsubmoduleを追加する時などに使うようです。

dependencies

基本的にCircleCiはrootにpackage.jsonやGemfileのようなファイルを置いとくと勝手にnpm installやbundle installを行ってくれます。
なので、何かオプションをつけて実行したい時や、package.jsonに記述していないけど別途なにかinstallしたい時などに記述します。

dependencies:
  override:
    npm install --production
  pre: 
    npm install coffeescript

ここで脱線しますが、override: 、pre: なる新しいキーが出てきました。
これはオプションで付与でき、CircleCiのデフォルトのコマンド実行を上書きしたり、前後に別のコマンドを入れることができます。

  • override: デフォルトのコマンドを上書き

  • pre: CircleCiのデフォルトコマンド実行前
    上で説明した通りデフォルトではnpm installが自動的に呼ばれるのでpreはその前に実行されるということです

  • post: CircleCiの実行後デフォルトコマンド

※ちなみにデフォルトと書いてますが正式にはCircleCiの推測に基づくデフォルトコマンドです。 CircleCi「package.jsonがあるから、npm install 呼んどくか」のような推測だと推測しました。

database

これも使ったことないので、詳しくないのですが、sampleだとテストデータとかをsqlとかでinsertしたい場合に使うようです

database:
  override:
    - mysql -u ubuntu circle_test < my-database-setup.sql

sampleまるまる持ってきましたがこんな感じです。

test

ここも基本的には言語に沿ったtestを実行してくれますが、足りない場合に記述します。

test:
  pre: 
    - echo "-----start test-----"
  override:    
    - go test -cover  
  post: 
    - echo "-----end test-----"

deployment

これもそのままですが、deployのコマンドを記述します。

deployment:
  deploy:
    branch: master
    commands:
      - make build
      - make deploy

branchはCircleCiに登録しているプロジェクトのブランチを。
commandsはそのままで、deployのためのコマンドを記述するだけです。

以上でcircle.ymlの基礎は終了です。 より詳しい情報はドキュメントを参照してください。
公式のsampleのymlはこちらです。

例の言語がgoやらrubyやら混在してたり、後半明らかに失速して雑になってしまいましたが、とりあえず基本的なところは押さえられたんじゃないかと。
何か間違ったこと書いてありましたら指摘していただけると幸いです

シェル②パイプライン

前回に引き続き調べにくいコマンドパイプライン | (縦棒)について
これは複数のコマンドを実行したいときに使います

例: カレントディレクトリの.dmgだけを調べたいとき

ls | grep dmg

とするとlsで表示されるファイルの中からdmgファイルだけが絞られて表示される。
応用して

ls | grep dmg | xargs rm -rf 

とするとカレントディレクトリのdmgファイルをすべて削除できる。
ちなみにxargsは前のパイプラインの結果を標準入力として次のコマンドの引数に渡すコマンド。

さらに応用して

find ~ -name "*.dmg" -o -name "スクリーンショット*" | xargs rm -f

みたいな感じで書いて、macのlaunchd使ってゴミファイルを定期的に削除するものを作ったりもできそう。

シェル①リダイレクト

シェル関係で触ったことを

調べてもなかなか出なかったリダイレクトについて書きます。 リダイレクトは<(小なり),>(大なり)と書きコマンド入力の出力先や入力元を変更できます。

echo "hogehoge" > hoge.txt

これはechoで本来表示されるhogehogeをhoge.txt内に書く(出力)動きをします。

逆に入力は

test.txt

b
c
a
d
e

こういうテキストファイルがあった時に

sort < test.txt

a
b
c
d
e

という風にtest.txtのデータを読む(入力)してsortを行います

もちろん組み合わせることも可能で、

sort < test.txt > sorted.txt

とやるとsortされたものがsorted.txtに出力されます。

これがリダイレクトです。

また>> << というものもあって >> は出力先の末尾に追記(出力先のファイルがない場合は新規で作成される)、 <<はEOFで始まってEOFで終わるまでの情報を入力できる

sort << EOF
b
c
d
e
a

EOF

a
b
c
d
e

という感じ

Goのsliceをredisで管理する

Goで作成したSliceをredisで管理しようとして結構はまったのでメモ。

商品のSliceを作成し、それをredisに入れて取り出すところまで

import (
    "encoding/json"
    "github.com/garyburd/redigo/redis"
)



type Product Struct {
    Id     uint
    Title  string
    Price  uint
}


type ProductData Struct {
    ProductSlice []Product
}

productData := ProductData{}
product := model.Product{}
// 商品データを取得してSliceに追加
product.findProducts(&productData.ProductSlice)

// jsonに変換
bytes, _ := json.Marshal(productData)

//jsonをredisに追加
conn.Do("SADD", "key", bytes)

これでredisに保存完了

取り出すときは

//redisから取得
data, _ := redis.Values(conn.Do("SMEMBERS", "key"))
bytes, _ := data[0].([]byte)

productData := ProductData{}
// jsonからsliceに戻す
json.Unmarshal(bytes, &productData)

で取得。