ksaitoの日記

日々試したことの覚え書き

docker cp の代替え

docker cp でコンテナからファイルを取り出す場合、パスやファイルパーミッション、オーナによって失敗することがあります。

取り出す場合は、下記のようなdocker exec と tar を使ったほうがいいかもしれません。

対象を下記のコマンドで確認します。

TARGET_DIR=<ファイルのあるディレクトリ>
CONTAINER_NAME=<対象のコンテナ>
docker exec -w $TARGET_DIR $CONTAINER_NAME tar cf - * > target_files.tar

Makefileで複数の必須パラメータをチェックする方法

やりたいこと

下記のようなMakefileがあります。

target:
        @echo PARAM1=$(P1)
        @echo PARAM2=$(P2)

実行するとパラメータのP1P2を処理に組み込むことができます。

$ make
PARAM1=
PARAM2=
$ make P1=aaa
PARAM1=aaa
PARAM2=

2つのパラメータが指定されなかったらエラーメッセージを表示して、何も処理しないで終了したい。

解決方法

いろいろ試した結果、下記のように実装しました。

target:
ifndef P1
        $(target-usage)
endif
ifndef P2
        $(target-usage)
endif
        echo PARAM1=$(P1)
        echo PARAM2=$(P2)

define target-usage
        @echo "P1=<必須のパラメータ>"
        @echo "P2=<絶対に指定するパラメータ>"
        @echo "Usage: make target P1=$$P1 P2=$$2"
        @exit 1
endef

下記の通り、やりたいことは実装できました。

$ make P1=aaa
P1=<必須のパラメータ>
P2=<絶対に指定するパラメータ>
Usage: make target P1=aaa P2=
Makefile:6: recipe for target 'target' failed
make: *** [target] Error 1
$ make P1=aaa P2=bbb
echo PARAM1=aaa
PARAM1=aaa
echo PARAM2=bbb
PARAM2=bbb

本当は、下記のようにifndefにAND条件を書きたかったのですがだめでした。

target:
ifndef P1 && P2
        $(target-usage)
endif
        echo PARAM1=$(P1)
        echo PARAM2=$(P2)

define target-usage
        @echo "P1=<必須のパラメータ>"
        @echo "P2=<絶対に指定するパラメータ>"
        @echo "Usage: make target P1=$$P1 P2=$$2"
        @exit 1
endef

AWS EKSへのアクセス

EKSのクラスタにアクセスするには、VPCの中にあるEC2からIAMロールで権限を付与するのが安全です。

どうしてもVPCの外からアクセスする必要がある場合は、下記のようにします。

EKS用のIAMユーザを作成

  1. IAMでEKS専用のグループを作成しEKSの操作に必要な権限を付与
  2. IAMでプログラムによるアクセスのみ許可したIAMユーザを作成し上記グループに追加

アクセスキーの作成

作成したユーザでユーザのアクセスキーを作成します。

言うまでもありませんが、作成したアクセスキーは厳重に管理する必要があります。

kubeconfigの作成

awscliは、下記のバージョンで試しました。

$ aws --version
aws-cli/1.17.5 Python/3.6.8 Linux/4.9.184-linuxkit botocore/1.14.5

aws --profile eks configureで作成したアクセスキーを登録します。

$ aws --profile eks configure
AWS Access Key ID [None]: アクセスキー
AWS Secret Access Key [None]: シークレットキー
Default region name [None]: ap-northeast-1
Default output format [None]: json
$ export AWS_DEFAULT_PROFILE=eks
$ aws eks list-clusters --query 'clusters[]' --output table
--------------
|ListClusters|
+------------+
|  sample   |
+------------+

下記のコマンドでkubeconfigを作成します。

CLUSTER=sample
aws eks update-kubeconfig --name $CLUSTER

動作確認

接続先を確認します。

$ kubectl config current-context 
arn:aws:eks:ap-northeast-1:******:cluster/sample

あとは、普通にkubectlが利用できます。

$ kubectl get node
NAME                                              STATUS   ROLES    AGE     VERSION
ip-10-15-82-136.ap-northeast-1.compute.internal   Ready    <none>   4d22h   v1.14.7-eks-1861c5
ip-10-18-16-88.ap-northeast-1.compute.internal    Ready    <none>   4d22h   v1.14.7-eks-1861c5

後片付け

使い終わったらかならず、IAMユーザのアクセスキーを失効させます。

以上

bashの定義済み関数を確認する

下記のコマンドでbashの定義済みの関数を確認します。

declare -f

実行するとこんな感じです。

$ declare -f | head
__docker_append_to_completions () 
{ 
    COMPREPLY=(${COMPREPLY[@]/%/"$1"})
}
__docker_client_is_experimental () 
{ 
    __docker_fetch_info;
    [ "$client_experimental" = "true" ]
}
__docker_complete_capabilities_addable ()

コンテナ起動時にシェルだけで、環境変数でファイルを書き換える

コンテナ起動時にシェルだけで、環境変数でファイルを書き換える方法です。

下記のようなファイルを準備します。 ${VAL1}の部分を環境変数で書き換えます。

$ cat test.tmpl 
aaa
bbb
{${VAL1}}
ccc
$

下記のように、コンテナ起動時に-eオプションでVAL1に書き換えたい値を環境変数として、指定します。

$ docker run --rm -e VAL1="$(date)" -v .:/mnt --workdir /mnt nginx:1.17.4 /bin/bash -c 'eval "echo \"$(cat test.tmpl)\"" > /tmp/test.txt && cat /tmp/test.txt'
aaa
bbb
{2019年 10月 12日 土曜日 08:11:47 JST}
ccc
$

-v--workdirオプションは、今回の検証用でカレントディレクトリをマウントしましたが、コンテナに書き換えるファイルをCOPYすれば不要です。

書き換えの処理は、shbashevalを使います。

echoコマンドは、文字列の環境変数を置換してくれます。

$ echo $VAL1
okok
$ eval "echo \"$(cat test.tmpl)\""
aaa
bbb
{okok}
ccc
$

下記のようにテンプレートファイルとentrypoint用のシェルを準備します。

$ cat Dockerfile 
FROM nginx:1.17.4

COPY test.tmpl /mnt/test.tmpl
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
$ cat entrypoint.sh
#! /bin/bash

eval "echo \"$(cat /mnt/test.tmpl)\"" > /tmp/test.txt
cat /tmp/test.txt
$

下記のようにシェルだけで書き換えができました。

$ docker run -e VAL1="$(date)" --rm test /entrypoint.sh
aaa
bbb
{2019年 10月 12日 土曜日 08:43:05 JST}
ccc
$

eksctlをコンパイルする

eksctlのソースをコンパイルしました。

golang 1.12以上の環境がなかったので、コンテナでやりました。

コンテナの準備

コンテナは、下記の通り準備しました。 golangのオフシャルコンテナには、makeやgitがインストールされているので、ほとんど手を加える必要はありませんでした。

$ cat Dockerfile 
FROM golang:1.12.6

RUN mkdir -p /root/.ssh \
 && chmod 700 /root/.ssh
RUN apt-get update && apt-get install -y \
    time \
 && apt-get -y autoremove && rm -rf /var/lib/apt/lists/*

WORKDIR /root
$ docker build -t golang-dev .

実行とビルド

ドキュメントに従って、実行します。

$ docker run -it --rm golang-dev bash
root@b97e7c15991d:~# cd src
root@b97e7c15991d:~/src# git clone https://github.com/weaveworks/eksctl.git
root@b97e7c15991d:~/src# cd eksctl/
root@b97e7c15991d:~/src/eksctl# make install-build-deps
...
root@b97e7c15991d:~/src/eksctl# make test
...
root@b97e7c15991d:~/src/eksctl# make eksctl
make: 'eksctl' is up to date.
root@b97e7c15991d:~/src/eksctl# ./eksctl version
[ℹ]  version.Info{BuiltAt:"1562335031", GitCommit:"0.1.34-294-g4041d65a", GitTag:""}
root@b97e7c15991d:~/src/eksctl#

コンパイルには、結構、時間がかかりました。