しおブロ!

ITの知見や備忘録、レビューなど。しおぽん(shiopon01)のブログ

Golang ことはじめ

Golangはシンプルな言語仕様であり、習得が比較的容易な言語だ。
非知的なプログラマのためにデザインされており、プログラムを無意味に複雑にしてしまう機能は削除されている。 (継承やGenerics、for以外のループなどが削除されている)

サンプルコード

package main

import f "fmt"

func main () {
  f.Printf ("HELLO\n")
}

このソースコードをbuildすると、期待通り HELLO が出力される。

$ go build main.go && ./main
HELLO

ここで行っていることは、パッケージ節でのこのファイルが属するパッケージを指定、入出力フォーマットを実装した fmtパッケージ のインポート、main関数で Print 関数を使用した出力だけだ。

package

Go言語のプログラムは、複数のパッケージをひとつにリンクすることによって作られる。また、各パッケージは、そのパッケージに属する定数、型、変数、関数を定義しているひとつ以上のソースファイルから構成される。

Go言語のプログラムは、 mainパッケージ と呼ばれる、他からインポートされることがないパッケージをリンクすることで完成する。事実上、このmainパッケージから全てのパッケージが直接的・間接的にインポートされることになる。
mainパッケージは、パッケージ名を main にし、引数と戻り値を持たない main関数 を宣言していなければならない。

package main

func main () { ... }

プログラムの実行はmainパッケージを初期化した後、main関数を実行することで開始される。main関数を抜けた時点でプログラムは終了する。

import

インポート宣言では、他のパッケージを読み込むことができる。

import f "fmt"

インポートするパッケージにはエイリアスを付けることができ、ここでは f"fmt" パッケージのエイリアスとして利用している。パッケージと同名で利用する場合はエイリアスが必要なく、エイリアス名を省略した場合はソースコード内で fmt.Print などとして利用できる。

func main

Go言語の関数の定義には func キーワードが利用され、mainはGo言語の関数として定義される。

main関数にコマンドライン引数を渡したい場合、先述のようにmain関数に引数を渡すことは出来ないが、この場合は os パッケージや、 flag パッケージを利用することで受け取ることが出来る。

main以外の関数を自由に定義することも可能で、この場合は引数や戻り値を定義することができる。

参考

ニコニコ(く)

この記事、ユーザのコンテンツを持ち上げるだけで、根本的な動画配信部分を改善してこなかった現在のニコニコと、新しく発表された(く)がなぜ批判されているのかについて、よく纏められていると思った。

anond.hatelabo.jp

その中での取締役のこのツイートは、炎上しなかったにしろ、いろいろと問題があるように感じる。

確かに、誰が見てもよく分からないものだったし、明らかにお茶を濁すだけの機能だった。
しかし、それをたとえユーザ目線だったとしても、取締役の自分がGO出してリリースする機能を、発表してすぐ、そう言うのはニコニコの方針にたいして全てのユーザが不信感を抱く発言だっただろう。

数ある批判に耐えかねた中での発言での、言葉の選択ミスだとは思われるが、サービス提供者としてこれはさすがに問題であった。

ただ、今のツイートの流れを見ていれば分かる通り、これからはニコニコ動画として、ユーザと真剣に向き合ってサービスを作る姿勢でいくといった発言をしている。
社員の技術力の高いことに定評のあるドワンゴだし、今は上層部が舵取りをミスってるだけな気もするので、このへんも含めて今後にもうちょっと期待してみたい。

(でも、新しい機能を発表しただけでここまでユーザからフィードバックを貰えるって、やっぱりニコニコ愛されてるなと思った。。)

(延長無料くれ)

コピペプログラマー

コピペプログラマーとは、思うに、頭の中のコンピュータを鍛えられるプログラミング教育を受けてこなかった、受動的なプログラマーの成れの果てなのではないか。(この記事でも、プログラミングの習得方法に問題があったのでは、と言われている)

kuranuki.sonicgarden.jp

自分もプログラミングの授業は沢山受けたが、頭の中のコンピュータを鍛える教育はごく一部であり、プリントや教科書に写ったプログラムを写経するだけの授業も沢山あった。写経させるだけのプログラミング教育で給料を貰えるなんて、いい仕事だ。

まともなプログラマーになろうとするならば、とりあえず、コンピュータと仲良くなるところから始めれば良い。一般的に、初歩的なコンピュータサイエンスを学ぶことがこれに当たる。コンピュータとは、5大装置とは、2進数とは、…などを学び、コンピュータの気持ちをなんとなく理解できるようになろう。これ自体はプログラミングに直接関係無いことかもしれないが、プログラミングをやる上では大切なことだと思う。

その上でプログラミングを学び、例えば、記事にあった以下の問題。

英語で書かれた文字列中に含まれる英単語の個数を単語ごとにカウントする

これを見て、「頭から、文字列の長さ分調べよう」「スペースで区切って単語をカウントしよう」などがすぐに思いつくなら、もうコンピュータと仲良くなりつつある。もしあなたがコピペプログラマーだったなら、多少努力すればすぐに脱出できると思う。もしそうでないなら、アルゴリズムの勉強を始めるべきだ。また、それと同時に、プログラミング言語で何を出来るのかも知ろう。

アルゴリズム車輪の再発明によって簡単に、比較的楽しく学ぶことができるだろう。代表的なものではソート系、文字列の検索や挿入になる。ハノイの塔やエラトステネスの篩はもはやアルゴリズムの勉強の域ではない気がするので、推奨はできない。

Dockerfileの利用手順

目次

概要

VMを使ってチームメンバー全員が同じ開発環境を整えようとすると、とにかく手間がかかる。Vagrantで生成した400MB以上あるboxファイルを全員に配布しても良いが、利用していく中で好き勝手にカスタマイズされ、気付けば全く別の環境で開発していたという状態もあり得ない話ではない。

そこで、Dockerfileの出番がある。Dockerfileは、全ての環境で同じDockerのイメージを作成するための設定ファイルだ。実態は、ただのテキストファイルである。

このテキストファイル1つで、DockerHubから指定のイメージの取得とコンテナの作成、記載されたコマンドを実行、環境変数を変更し、全く同一の環境を整えてくれる。そこで整えたものを、新しい一つのイメージとして提供してくれるのがDockerfileの役割だ。

以下の例では、ruby:2.4.2のイメージを元に、nodejsの9系をインストールできる。
最後は環境変数ROOTに設定されたディレクトリに移動しているので、このDockerfileから生成されたイメージで作られたコンテナは、/var/wwwからスタートする。

FROM ruby:2.4.2

RUN curl -sL https://deb.nodesource.com/setup_9.x | bash
RUN apt install -y nodejs

ENV ROOT /var/www
WORKDIR $ROOT

大まかな使い方は公式リファレンスが丁寧に書いてくれているので割愛。
ここには、ややこしいCMDとENTRYPOINTADDとCOPYの違いを記載する。

Dockerfileリファレンス

起動時コマンド、CMDとENTRYPOINT

Dockerfileにこれを記述することで、そのイメージのコンテナを実行する際に実行するコマンドを設定できる。ここでbashを設定しておけば、docker runする時にわざわざ指定しなくても良いということになる。
例えば、こんな感じで設定する。

CMD ["ping","127.0.0.1","-c","100"]
ENTRYPOINT ["ping","127.0.0.1","-c","100"]

1つのDockerfile内では、CMDとENTRYPOINTはそれぞれ1回ずつしか使えない。併用は可能になっている。(複数記載されている場合、最後のコマンドが実行される)

CMDで指定したコマンドは、Docker run時に指定したコマンド指定で上書きされてしまう。

$ docker run --rm ubuntu cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"

ENTRYPOINTで指定したコマンドは、Docker run時に指定したコマンド指定で上書きされない、というのが大きな違いだ。 ただし、ENTRYPOINTでもdocker run --entrypoint=""を使用されると上書されてしまうので注意。

$ docker run --rm ubuntu cat /etc/debian_version
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.028 ms

["command"]とcommandの違い

起動時のコマンドでも2種類あったが、さらにそれぞれ2種類の書き方がある。 括弧で囲む書き方と、括弧で囲まない書き方だ。

括弧で囲んだコマンドは、シェルを介さずにコマンドが実行される。["command"]
一般的にはこちら使われる。

CMD ["ping","127.0.0.1","-c","100"]
ENTRYPOINT ["ping","127.0.0.1","-c","100"]

#=> ping 127.0.0.1 -c 100

括弧で囲まないコマンドは、シェルを介してコマンドが実行される。

CMD ping 127.0.0.1 -c 100
ENTRYPOINT ping 127.0.0.1 -c 100

#=> /bin/sh -c ping 127.0.0.1 -c 100

特徴を活かして併用する

CMDENTRYPOINTを両方書いた場合、連結されて1行のコマンドとして扱われる。
コマンドのみ固定にしておいて、引数を変更するなどの使い方ができる。

ENTRYPOINT ["ping"]
CMD ["127.0.0.1", "-c", "50"]

こう書くことで、dcoker runの際にコマンドは書き換え不可、引数を書き換え可能にできる。
引数が無い場合は127.0.0.1pingが送られ、引数がある場合はそのIPにpingを送るコマンドだ。

$ docker run ubuntu localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.027 ms

(DockerfileにENTRYPOINTを書かなかった場合、docker-compose.ymlに下記のように追記することで、サービスの全ての設定が終わった後に実行するコマンドを設定することが出来る。)

app-name:
  command: node app.js

ファイルの転送、ADDとCOPYの違い

ADD [ソース] [送信先]で、ホストに存在するファイルやディレクトリをコンテナにコピーできる。このソースファイルがtarアーカイブであった場合、自動的に解凍・展開される。

ADD default.conf /etc/apache2/sites-available/default.conf

COPY [ソース] [送信先]で、ホストに存在するファイルやディレクトリをコンテナにコピーできる。こちらはtarを展開しない。

ADD default.conf /etc/apache2/sites-available/default.conf

ほとんど同じなので、ADDCOPYを明確に使い分ける必要はない。(ADDだけでよさそう)

Dockerのインストールと利用手順

目次

概要

Dockerとは、仮想化技術「コンテナ」を利用したOS仮想化ツールだ。
VMWareなどのホスト型(OSに土台となるソフトウェアをインストールしてその上で仮想OSを立ち上げる)とは違い、OSの一部のみを仮想化して利用するため、非常に軽量に扱える。
さらに、各コンテナはアクセスできるリソースや権限を制限/分離したホストOSの「プロセス」として扱われるため、コンテナを管理するコストはプロセス管理とほとんど変わらない。
コンテナはホストOSのLinuxカーネルを共有するので、カーネルとコンテナの関係はJVMとJarに近い。(Docker for Windowsでは、LinuxカーネルHyper-Vで動かしているっぽく、少し手間。Linux系での利用を推奨)

Dockerのインストール方法

おおまかなインストール手順は以下の通り。ふつう、Docker Community Edition (CE)を利用する。

Install Docker | Docker Documentation

Windows

Docker for Windowsをインストールする。
基本的にはインストール手順に従っていけば良いが、WindowsではHyper-Vを有効にしなければならない。

Install Docker for Windows | Docker Documentation

Mac

Docker for Macをインストールする。
ほんとうにそれだけで動いたと思う。

Install Docker for Mac | Docker Documentation

Linux

これも公式のドキュメントにあるやつでだいたいOK。
しかし、そのままだとdockerコマンドの利用にsudoが必要になるので、ユーザーをdockerグループに入れてあげる。

Ubuntuだと、こんなかんじで。

sudo apt -y install apt-transport-https ca-certificates curl 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 update
sudo apt -y install docker-ce
sudo groupadd docker
sudo usermod -aG docker $USER

Get Docker CE for Ubuntu | Docker Documentation

利用手順

とりあえず利用してみるのが一番早い。

Dockerでコンテナを作成するためには、まずコンテナを作成するための型であるイメージが必要だ。イメージがたい焼き器なら、コンテナがたい焼きという認識で問題ない。

イメージはDockerHubという公式のイメージ共有サービスからダウンロードすることができる。まず、目的のイメージを検索する。今回は練習で、ubuntuのイメージをダウンロードして使ってみる。検索する時はdocker searchが使える。

(イメージはブラウザのDockerHubで探したほうが楽)

https://hub.docker.com/

docker search ubuntu

今回はOFFICIALの、公式が出しているubuntuイメージを利用する。
DockerHubのイメージをローカルに落としてきたい場合はdocker pull [イメージ名]が使える。この時、ubuntu:17.04のようにタグを指定すれば、指定のタグのバージョンを手に入れる事ができる。何も付けなければ、latest (最新)のイメージが手に入る。

docker pull ubuntu

今までにダウンロードしたイメージはdocker imagesで確認できる。この時に表示されるREPOSITORYIMAGE IDを指定して、イメージの削除も可能。

docker images
docker rmi [指定イメージ]

コンテナの生成と起動はdocker run [イメージ名]で行う。しかし、役目を終えたdockerのコンテナすぐに消えてしまうので、このままでは何も起こらない。イメージ名の後に、実行したいコマンドが必要になる。例えば、さっきダウンロードしたubuntu:latestecho 1を実行する場合。

docker run ubuntu echo 1

コマンドを指定するとubuntu1を出力して、消えてしまう。消えると言っても実際は消滅しているわけではなく、コンテナのステータスがExitedになって寝ているだけだ。その様子は、docker ps -aで確認できる。この時に表示されるCONTAINER IDを指定して、コンテナの削除が可能。

Exitedのコンテナがたまっていくのは嫌なので、コンテナの終了時にコンテナは削除したい。その時は、runコマンドの--rmオプションが利用できる。

docker run --rm ubuntu echo 1

また、起動したコンテナの中に入って作業をしたいという場合もある。この場合、-itオプションが利用できる。

  • -i 対話モードでコンテナを起動
  • -t 疑似ターミナルでコンテナを起動
docker run -it --rm ubuntu echo 1

この時に表示される1は、dockerの疑似ターミナル内で表示される1になる。しかし、役目を終えたコンテナはすぐに消滅してしまう。ほんとうに中で作業をしたいなら、bashなどのshellを起動しよう。
exitなどでshellを抜けることで終了できる。

docker run -it --rm ubuntu bash

docker runのオプション

  • -d デタッチドモード(デーモン)でコンテナを起動
  • -i 対話モードでコンテナを起動
  • -t 疑似ターミナルでコンテナを起動
  • -v Data Volumeの指定(所謂、フォルダ共有)
  • -w 開始ディレクトリの指定(デフォルトはルート)
  • --name [名前] : コンテナに名前をつける:
  • --rm コンテナの終了時にコンテナをクリーンアップし、ファイルシステムを削除する
  • --reset [ポリシー] : 再起動ポリシーを設定(no, always, など)
  • -p ポートのバインド(例: 80:8080ならホスト80番でコンテナ8080番)
  • -e 環境変数設定(RAILS_ENV=development)

普通にdockerコマンドで利用するくらいなら、-it --rmくらいしか使わない(たぶん)。
その他はほとんど、docker-compose(後述)の設定ファイルで設定する。

よく使うコマンド

先述した、疑似ターミナルの対話モードでbashを起動など。
停止しない状態で元のターミナルに戻りたい(コンテナからデタッチ)なら Ctrl + P + Qを押せば良いらしい。

docker run -it --rm [image] bash

コンテナが増えた場合、このコマンドで全コンテナを削除できる。

docker rm $(docker ps -aq)

VMWareのUbuntuを入れ直したときのメモ

とりあえずUbuntuの情報を見たい

cat /etc/lsb-release # check Ubuntu version
df -h   # check Disk capacity
free -m # check Memory capacity

英字の設定

sudo dpkg-reconfigure keyboard-configuration

…を実行したのだが、そのターミナルを離れるとまた日本語入力に戻っている。。
結局、「システム設定」→「キーボードレイアウト」の入力ソースを「英語(US)」にするだけでよかったらしい。

フォルダ共有(VMWare

仮想マシン設定のオプションから「共有フォルダ」で、ホストマシンとの共有フォルダを設定。

インストール作業

VMWare Tools(VMWare

VMWare Workstation Playerの場合「Player>管理>VMWare Toolsのインストール」から

アップデート

sudo apt upgrade
sudo apt update

よく使うやつ

treeコマンドがコマンドで一番すきです。

sudo apt -y install tmux emacs24 vim htop tree

VSCode

vscode-doc-jp.github.io

SQLite3

sudo apt -y install libsqlite3-dev sqlite3

chrome

sudo apt install libappindicator1
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome-stable_current_amd64.deb

ruby

rubyのバージョン管理ではrbenvをずっと使っている。

sudo apt install -y rbenv libssl-dev libreadline-dev zlib1g-dev
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
rbenv install --list
rbenv install [version]
rbenv global [version]

gem install bundler railties rails && rbenv rehash

node

nodeのバージョン管理ではrbenvみたいなnodenvをずっと使っている。

git clone git://github.com/nodenv/nodenv.git ~/.nodenv
git clone git://github.com/nodenv/node-build.git ~/.nodenv/plugins/node-build
echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(nodenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
nodenv install --list
nodenv install [version]
nodenv global [version]

docker

sudo apt -y install apt-transport-https ca-certificates curl 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 update
sudo apt -y install docker-ce
sudo groupadd docker
sudo usermod -aG docker $USER

BIOSが起動しなくなった時にやったこと

先日、GTX670をGTX1070に換装した際にBIOSが起動しなくなった。
結局のところ原因はメモリにあったようで、メモリを外して解決したのだが、そこに至るまでの過程を記述しようと思う。
メモリが悪かったのか、ボードのソケットが悪かったのかはまだ確かめていない。新しいGPUでゲームをしたかった。

PC掃除から換装まで

GPUを換装する前に、PCの中があまりにも汚かったので、ファン、電源、ボード上のホコリの塊などを掃除した。この際、CPUファンを取り外してグリスを塗り直した。
今思えば、ここで起動確認をしておけばよかったのだと思う(おそらく、この時点でもうメモリか、ソケットは死んでいたのだろう)

そのままGPUを換装して電源を入れると、ファンが全力で回転して止まらなくなった。つまり、BIOSが起動しなくなっていた。

BIOSの死から原因特定まで

構成が変わったとかで起動しないのかと思い、とりあえずCMOSクリアしてみたが起動せず。

それならとグラボの不良を疑い、とりあえずGTX1070を外して電源を入れてみた。
起動しない。グラボの問題でないことが判明。この時にSOUND BLASTER Zも抜いた。

個人的にはCPUが怪しかった。CPUファンを設置する際、不手際(または静電気)で壊してしまったのではないかと心配だった。
確認のためにCPUを外して電源を入れた時、PCは3秒ごとに再起動を繰り返した。挙動が違うので、おそらくCPUは壊れていない。

ケーブルの接触不良も怪しかったので、刺し直してみる。起動しない。

とりあえず全部外そうと思い、SSD、HDDを外したがこれでもダメ。
ここで、4枚刺さっているメモリを1枚にしたところ、起動できた。

今までずっと挿しっぱなしで今まで動いており、今回の作業ではまったく触れていない場所だったので意外だった。
とりあえず、刺したら起動しなくなるメモリを見つけ、それを外すことで復活。(サクっと書いてあるが、ここに至るまでにけっこう時間がかかった)

やったことは大体こんなかんじで、よくあるやつ。取り出すのがめんどくさかったので、マザーボードはケースに入れたまま作業を行った。
どのパーツも5年は使っており、最悪、全部換装まであるなと考えていたので、出費がかさばらなくて嬉しい。。

構成

メーカーが分からないものがいくつかあるが、とりあえず構成も。