memo.log

技術情報の雑なメモ

Docker と Nginx でリバースプロキシを構成する最低限のメモ

前提

  • 構成は以下のイメージ
    • ホストで80番ポートで受ける、DockerのNginxは80番ポートで受ける、後ろに80番ポートで流す
  • docker はインストール済であること、後ろのサーバは動いていること
  • Amazon Linux2
    • Linux ip-172-31-4-104.ap-northeast-1.compute.internal 4.14.219-161.340.amzn2.aarch64

f:id:kuredev:20210222195409p:plain

手順メモ

①Nginx設定ファイル作成

素のNginxの設定ファイルから持ってきつつ、リバプロっぽい設定を入れた。 ポイントは include /etc/nginx/conf.d/*.conf; を削除したところだったぽい。 もともとDockerでNginxを起動するとコンテナ内でこの /etc/nginx/conf.d/*.conf; ディレクトリに設定ファイルが合ってそちらも読み込まれてしまうとうまくリバプロとして動かなかった。

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;

        location /test {
            proxy_pass http://[後ろのサーバのIPアドレス]/;
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}

②Dockerファイル作成

[ec2-user@ip-172-31-4-104 docker]$ pwd
/home/ec2-user/docker
[ec2-user@ip-172-31-4-104 docker]$ ls
Dockerfile  nginx.conf
[ec2-user@ip-172-31-4-104 docker]$ cat Dockerfile
FROM nginx:latest

ADD ./nginx.conf /etc/nginx/nginx.conf

③ Docker のイメージ作成、コンテナ作成、コンテナ起動

$ sudo docker build -t nginx-img ./
$ sudo docker create --name nginx-container -p 80:80 -it [Image ID]
$ sudo docker start [Container ID]

※③' docker-composer でコンテナを実行する場合

以下のように設定ファイルを準備し、実行

[ec2-user@ip-172-31-4-104 docker]$ cat docker-compose.yml
version: '3'
services:
  nginx:
    build: .
    ports:
     - "80:80"
[ec2-user@ip-172-31-4-104 docker]$ sudo docker-compose up

④動作確認

外からDocker/Nginxのサーバに向けて

http://[IP Addr]/test

で後ろのサーバのコンテンツが返ってくるはず。

参考

nginx https://hub.docker.com/_/nginx

【Docker】Nginxのconfで環境変数を使う - Qiita https://qiita.com/jungissei/items/2d6b40320b520f52b502

Compose を始めましょう — Docker-docs-ja 19.03 ドキュメント https://docs.docker.jp/compose/gettingstarted.html#dockerfile

【Ruby】数値と文字列の変換メモ

文字列→数値

基本形 
> "10".to_i
=> 10

整数とみなせない文字があればそこまでを変換対象とします。変換対象が空文字列であれば 0 を返します。
> "a".to_i 
=> 0

基数の指定が可能(レシーバの文字列を基数の数値と解釈して返却する)
> "10".to_i(2) 
=> 2 
> "10".to_i(16) 
=> 16
> "0x10".to_i(0) 
=> 16

数値→文字列

0 - 31 の制御文字の場合は表現できないので、16進数で表示されるみたい ord で戻せる

そのまま文字にする
irb(main):068:0> 1.to_s 
=> "1" 
irb(main):069:0> 01.to_s 
=> "1" 
irb(main):070:0> 0x10.to_s 
=> "16"
> 10.to_s(16)
=> "a"

エンコーディング
irb(main):054:0> 1.chr 
=> "\x01" 
irb(main):055:0> 65.chr 
=> "A" 
irb(main):056:0> 65.chr.encoding 
=> #<Encoding:US-ASCII> 
irb(main):057:0> 64.chr.encoding 
=> #<Encoding:US-ASCII> 
irb(main):058:0> 64.chr 
=> "@" 
irb(main):059:0> 63.chr 
=> "?" 
irb(main):060:0> 48.chr 
=> "0" 
irb(main):061:0> 31.chr 
=> "\x1F"
> 63.chr.ord 
=> 63
> p 10.chr Encoding::ASCII_8BIT # 文字コード指定
"\n"
irb(main):080:0> "kkk".length
=> 3
irb(main):081:0> "\x12\x12".length
=> 2
> "\x65\x01\x41".chars 
=> ["e", "\u0001", "A"]
irb(main):085:0> "kkk".chars 
=> ["k", "k", "k"] 
irb(main):086:0> "\x65".chars 
=> ["e"] 
irb(main):087:0> "\x65\x01".chars 
=> ["e", "\u0001"] 
irb(main):088:0> "\x65\x01\x64".chars 
=> ["e", "\u0001", "d"] 
irb(main):089:0> "\x65\x01\x14".chars 
=> ["e", "\u0001", "\u0014"] 
irb(main):090:0> "\x65\x01\x41".chars 
=> ["e", "\u0001", "A"]

irb(main):042:0> 10.chr
=> "\n"
irb(main):043:0> 10.chr.ord
=> 10
irb(main):044:0> 10.chr.ord.chr
=> "\n"
irb(main):045:0> 10.chr.ord.to_s
=> "10"
irb(main):046:0> 10.chr.ord.to_s(16)
=> "a"

irb(main):053:0> 121.chr
=> "y"
irb(main):054:0> 0x79.chr
=> "y"

参考

String#to_i (Ruby 3.0.0 リファレンスマニュアル)

【Linux】ネットワークインターフェースの番号(インデックス)を確認するコマンド

コマンド自体は極めてオーソドックス。 ip link show で表示される番号が該当してるっぽい。

 % ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen
 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default ql
en 1000
    link/ether 0a:16:53:d0:fc:80 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default ql
en 1000
    link/ether 0a:2b:38:3d:bb:0a brd ff:ff:ff:ff:ff:ff
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default ql
en 1000
    link/ether 0a:aa:c9:62:6e:fa brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT grou
p default 
    link/ether 02:42:dc:ed:12:78 brd ff:ff:ff:ff:ff:ff
6: br-5ec1c975db31: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFA
ULT group default 
    link/ether 02:42:f9:7d:c3:56 brd ff:ff:ff:ff:ff:ff

参考

sysfs - Is it possible to get network interface index not via /sys? - Unix & Linux Stack Exchange https://unix.stackexchange.com/questions/150216/is-it-possible-to-get-network-interface-index-not-via-sys

setsocopt探訪のメモ(5)

前回までは、 setsocopt 関数はOSのシステムコールを呼んでいるらしいというところまで確認した。 今回は、カーネルシステムコールの実装を覗いてみたいと思います。(確認した時のカーネルのバージョンは linux-4.19.172 kernel/git/stable/linux.git - Linux kernel stable tree

setsocopt で検索すると、以下のファイルにそれっぽい定義がありました。 linux-4.19.172/net/packet/af_packet.c

すると以下の箇所に今回焦点を当てているオプションの PACKET_ADD_MEMBERSHIP に関する処理の定義があります。

以下の copy_from_user はメモリ空間からカーネル空間に変数のメモリをコピーする関数です。 ここで (copy_from_user(&mreq, optval, len)) では文字列のポインタ optval を packet_mreq_max 構造体にコピーしています。 つまり、ここでデータを指定の構造体に入れ直していると考えて良さそうです。 したがって、 copy_from_user において文字列データとしてユーザー空間からデータを取得するため、ユーザー空間のプログラムでは構造体でも文字列データでも同じように処理が出来たと考えられます。 これで一旦最初の疑問は解消できたように思います!

static int
packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
{
    struct sock *sk = sock->sk;
    struct packet_sock *po = pkt_sk(sk);
    int ret;

    if (level != SOL_PACKET)
        return -ENOPROTOOPT;

    switch (optname) {
    case PACKET_ADD_MEMBERSHIP:
    case PACKET_DROP_MEMBERSHIP:
    {
        struct packet_mreq_max mreq;
        int len = optlen;
        memset(&mreq, 0, sizeof(mreq));
        if (len < sizeof(struct packet_mreq))
            return -EINVAL;
        if (len > sizeof(mreq))
            len = sizeof(mreq);
        if (copy_from_user(&mreq, optval, len))
            return -EFAULT;

amzn.to