ランダム生成されるコンテナ名について

# はじめに

コンテナを起動するとき、`--name`を指定しないとランダムでコンテナ名がつけらえます。下記でいうところの`great_wescoff`です。

```
$ docker run alpine:latest

$ docker ps -a
CONTAINER ID   IMAGE           COMMAND     CREATED          STATUS                      PORTS     NAMES
0772fae09ab1   alpine:latest   "/bin/sh"   16 seconds ago   Exited (0) 15 seconds ago             great_wescoff
```

ふと、この名前がどのように生成されているのか気になりました。

# 調べ方

オープンソースなのでそれ見れば答えがわかりますが、自分なりに調べてみて最後に答え合わせを行おうと思います。

調べ方は、`docker run`をたくさん実行して、(ほぼ)全通りの名前のパターンを抽出し、それを眺めて法則性を見つけて行こうと思います。

```
$ docker run -d alpine:latest
```
何かしらのイメージを実行します。実行するイメージはなんでもいいのですがなるべく軽量なものを選びました。
`-d` オプションは、コンテナをバックグラウンドで実行してくれるコマンドです。
ですが今回はその用途でなくコンテナIDを出力するために使います。

```
$ docker ps -a -f "id=$cid" --format "{{.Names}}"
```

先ほど出力したコンテナID(cid)を用いてコンテナ名を抽出します。
`-a`オプションで(実行中出ないものも含めた)全てのコンテナを表示させて、
`-f`オプションでコンテナIDでフィルタリングを行い、
`--format`で表示形式をカスタマイズします。

```
$ docker rm $cid
```

コンテナ名が抽出できたらあとは用無しなので削除します。

# いざ実行

#### スクリプト

上記のdockerコマンドを組み合わせてshellscriptを作成します。

`names`がコンテナ名のリストを格納しているファイルです。
1000件コンテナ名を取得して、1000件とも今まで蓄積してきたコンテナ名と重複してたら終了します。それまで無限ループします。

```shell

total=0
while true; do
    
    for i in `seq 1000`; do
        cid=$(docker run -d alpine:latest)
        docker ps -a -f "id=$cid" --format "{{.Names}}" >> names
        docker rm $cid > /dev/null
    done
    
    sort -u names -o names
    after_wc=$(cat names | wc -l | tr -d ' ')
    
    if [ "$total" = "$after_wc" ]; then
        exit
    else
        echo "continue (find new name: $(($after_wc-$total)))"
        total=$after_wc
    fi
    
done
```

#### 1日後、、、

処理が終わっていなかったので、少し高速化することにしました。一応この時点で、１エポックごとに新名が500件ほどに下がってきていたので、どこかで頭打ちにはなりそうです。

やはりdockerコマンドを実行している部分がネックなので、ある程度並列実行させることにしました。

```shell
total=0

get_name() {
    for i in `seq 100`; do
        cid=$(docker run -d alpine:latest)
        docker ps -a -f "id=$cid" --format "{{.Names}}" >> names
        docker rm $cid > /dev/null
    done
}
export -f get_name

while true; do

    seq 10 | xargs -I ZZ -P 10 sh -c get_name
    
    sort -u names -o names
    after_wc=$(cat names | wc -l | tr -d ' ')
    
    if [ "$total" = "$after_wc" ]; then
        exit
    else
        echo "continue (find new name: $(($after_wc-$total)))"
        total=$after_wc
    fi
    
done
```
名前を取得する部分を関数化させて10並列で実行させます。並列数は多ければ処理も高速化できることになりますが、PCスペックの関係か以下のエラーが頻出して、最悪の場合だとdockerが機能しなくなってしまいました。

```
Error response from daemon: You cannot remove a running container 54161ca2bea3d750a3e873a329a760af990dfcc115cb13ecec322cb2f3eff85a. Stop the container before attempting removal or force remove
```

```
ERRO[0003] error waiting for container: context canceled
```

100回繰り返しを10並列にしたこのバージョンでもたまに発生します。

#### 2日後、、、

結局このループは終わりませんでしたが、１エポックごとに新名が10個ほどしか見つからなくなってきたので、打ち切りました。ここで法則性を見つけていきます。

# 解析

仰々しく解析などといっていますが、抽出されたコンテナ名を眺めてこんな感じの法則ありそう、と考えるだけです。

見つかった名前の数は```25422```個。これにあと数百個は見つかっていない名前がありそうです。名前には、必ずアンダーバー(```_```)が入っていて、前後の単語を区切る文字のようです。この単語をリストアップしてみます。また、前後でこの単語は重複していないようですので、別々にリストアップします。

```
sed -e 's/_.*//g' names > names_first
uniq names_first names_first_uniq
```
<details>
admiring
adoring
affectionate
agitated
amazing
angry
awesome
beautiful
blissful
bold
boring
brave
busy
charming
clever
compassionate
competent
condescending
confident
cool
cranky
crazy
dazzling
determined
distracted
dreamy
eager
ecstatic
elastic
elated
elegant
eloquent
epic
exciting
fervent
festive
flamboyant
focused
friendly
frosty
funny
gallant
gifted
goofy
gracious
great
happy
hardcore
heuristic
hopeful
hungry
infallible
inspiring
intelligent
interesting
jolly
jovial
keen
kind
laughing
loving
lucid
magical
modest
musing
mystifying
naughty
nervous
nice
nifty
nostalgic
objective
optimistic
peaceful
pedantic
pensive
practical
priceless
quirky
quizzical
recursing
relaxed
reverent
romantic
sad
serene
sharp
silly
sleepy
stoic
strange
stupefied
suspicious
sweet
tender
thirsty
trusting
unruffled
upbeat
vibrant
vigilant
vigorous
wizardly
wonderful
xenodochial
youthful
zealous
zen
</details>

後方の単語はソートもしないといけないので、上記の抽出スクリプトで使っていたコマンドを流用。

```
sed -e 's/.*_//g' names > names_second
sort -u names_second -o names_second_uniq
```

<details>
agnesi
albattani
albattani2
allen
allen7
almeida
antonelli
antonelli6
archimedes
archimedes0
archimedes3
ardinghelli
aryabhata
aryabhata6
austin
austin3
babbage
banach
banzai
bardeen
bartik
bassi
bassi0
bassi2
beaver
bell
benz
benz9
bhabha
bhaskara
black
black0
blackburn
blackburn3
blackwell
bohr
booth
booth6
borg
bose
bose2
bose6
bouman
boyd
boyd4
brahmagupta
brahmagupta3
brahmagupta4
brattain
brattain8
brown
buck
burnell
burnell4
cannon
cannon3
cannon7
carson
carson8
cartwright
carver
cerf
chandrasekhar
chaplygin
chatelet
chatelet8
chatterjee
chaum
chebyshev
clarke
cohen
colden
colden4
cori
cray
cray5
curie
curie9
curran
curran2
darwin
darwin8
davinci
davinci3
davinci7
dewdney
dewdney1
dhawan
diffie
dijkstra
dijkstra4
dijkstra6
dirac
driscoll
driscoll1
dubinsky
easley
edison
einstein
elbakyan
elgamal
elion
elion8
ellis
engelbart
euclid
euclid4
euler
euler0
faraday
faraday5
feistel
feistel9
fermat
fermat2
fermi
fermi5
feynman
feynman2
franklin
gagarin
galileo
galois
ganguly
gates
gauss
germain
goldberg
goldstine
goldstine5
goldstine9
goldwasser
goldwasser9
golick
golick7
goodall
gould
greider
greider1
grothendieck
haibt
hamilton
haslett
haslett5
hawking
hawking7
heisenberg
hellman
hellman1
hermann
herschel
hertz
heyrovsky
heyrovsky0
hodgkin
hodgkin5
hofstadter
hofstadter7
hoover
hoover2
hopper
hugle
hypatia
ishizaka
jackson
jang
jemison
jennings
jennings9
jepsen
jepsen7
jepsen8
johnson
joliot
jones
jones2
jones7
kalam
kalam6
kapitsa
kare
kare8
keldysh
keldysh0
keller
kepler
kepler8
khayyam
khayyam5
khayyam9
khorana
kilby
kilby0
kirch
knuth
knuth5
kowalevski
lalande
lalande5
lamarr
lamarr8
lamport
leakey
leavitt
leavitt1
lederberg
lehmann
lewin
lichterman
liskov
lovelace
lumiere
lumiere1
mahavira
margulis
matsumoto
matsumoto9
maxwell
maxwell4
maxwell8
mayer
mccarthy
mcclintock
mclaren
mclaren2
mclaren5
mclean
mclean7
mcnulty
mcnulty8
meitner
mendel
mendeleev
meninsky
meninsky3
merkle
mestorf
mirzakhani
montalcini
montalcini7
moore
moore0
morse
moser
murdock
murdock4
napier
nash
nash2
neumann
newton
nightingale
nobel
noether
noether6
northcutt
noyce
panini
pare
pascal
pascal3
pasteur
payne
perlman
perlman3
pike
poincare
poitras
poitras3
proskuriakova
ptolemy
ptolemy6
raman
ramanujan
rhodes
ride
ride5
ritchie
robinson
roentgen
rosalind
rubin
saha
sammet
sammet4
sanderson
satoshi
shamir
shannon
shaw
shaw4
shirley
shockley
shtern
shtern1
sinoussi
snyder
solomon
solomon5
solomon7
spence
stonebraker
sutherland
swanson
swanson5
swartz
swartz6
swirles
taussig
tereshkova
tesla
tesla4
tharp
tharp0
thompson
thompson7
torvalds
torvalds7
tu
turing
varahamihira
vaughan
villani
visvesvaraya
visvesvaraya0
visvesvaraya3
volhard
volhard4
wescoff
wescoff1
wilbur
wilbur6
wilbur9
wiles
williams
williams1
williamson
wilson
wilson9
wing
wozniak
wozniak2
wright
wright5
wu
wu1
yalow
yalow0
yonath
zhukovsky
</details>

まだ出現していない単語がないとして、__これらの108個×350個の単語を組み合わせてコンテナ名は作られている__のでないかと推測します。

そうなると、組み合わせは`37800`個になりますので、スクリプトも非効率で試行回数が足りていなかったかなと反省です。


# 答え合わせ

上記で抽出した単語を頼りに、ソースコードを追いました。

https://github.com/moby/moby/blob/master/pkg/namesgenerator/names-generator.go

大枠は捉えられていたようですが、予想と違いました。__108個×237個の単語の組み合わせと、引数として与えられるリトライ数によっては、後ろにランダムで0~9の数字が付与される__でした。
(ただし、`boring`と`wozniak`の組み合わせはのぞく)

これを受けて、私が抽出した350個の後方の単語のうち数字が付与されているものを除くとピッタリ237個になります。つまり候補の単語は前後全て抽出できていたようです。

しかし、ランダムで付与される数字も含めて、理論上の組み合わせの総数は`(108*237-1)*11=281545`となり（しかも数字が付与される確率自体が低そう）、途方もないので打ち切って正解でした。

以上になります。ふと気になったことではありますが、調べているうちに(特にshellについて)勉強になることが多くなんだかんだ有意義な調査でした。