f99aq8ove's blog

実例で学ぶ CoreOS 超入門

tag: CoreOS and Docker
24 July 2015

このエントリは 2015-07-24 に書かれました。 内容が古くなっていたり、もはや正しくないこともありますので、十分検証を行ってください。

CoreOS とは?

Linux ディストリの1つです。

ざっくり言うと、OS 内のすべてのアプリケーションを Docker で動作させることを前提にしたディストリになっています。

特徴

OS アップデート

rootfs をパーティションごと交換する方式で、ブルーグリーンデプロイメント的にアップデートされます。アップデート後の再起動戦略は、etcd でロックをとって順番に再起動していくというような分散環境に適したものが選べます。

クラスタリング

先ほど簡単に触れましたが、etcd でクラスタリングする機能がデフォルトで組み込まれています。

分散システム fleet

ざっくり言うと、クラスタ上で動作する systemd の様なものです。例えばクラスタ内で 5 個、○○コンテナを起動させておくというような制御が可能で、フェイルオーバーも自動で行ってくれます。(らしいです。クラスタ機能は試せてないです。)

コンテナ

Docker が使用可能です。その代わり、普通のパッケージマネージャがありません。すべてのアプリケーションは Docker 上で動かすのが前提になっています。

実際に使ってみる

CoreOS の設定は cloud-config というものに記載して、デプロイ時に適用することができます。以下に、当 blog の作成時に使用した cloud-config を貼り付けます。

注意しないといけない点は、デフォルトではファイアウォールの設定がされていないところです。 外界に直に触れるサービス上で使う場合はそれなりに設定しておかないと大変なことになります。

なお、Digital Ocean 上にデプロイする場合は、CoreOS の droplet を作成後に user-data を貼り付ける箇所があるので、以下を貼り付けて待つだけでスグに使用可能になります。

user-data.yaml

#cloud-config

hostname: f99aq8ove.net

coreos:
  etcd:
    discovery: https://discovery.etcd.io/<key> #see https://coreos.com/os/docs/latest/cluster-discovery.html
    addr: $private_ipv4:4001
    peer-addr: $private_ipv4:7001

  update:
    reboot-strategy: reboot # アップデート時の再起動戦略。reboot は無条件再起動

  units:
    - name: timezone.service
      command: start
      content: |
        [Unit]
        Description=timezone

        [Service]
        Type=oneshot
        RemainAfterExit=yes
        ExecStart=/usr/bin/timedatectl set-timezone Asia/Tokyo
    - name: iptables-restore.service
      enable: true
      command: start
    - name: ip6tables-restore.service
      enable: true
      command: start
    - name: sshd.socket
      command: restart
      content: |
        [Socket]
        ListenStream=xxxx # ssh ポートを xxxx に変更
        Accept=yes
    - name: etcd.service
      command: start
    - name: fleet.service
      command: start
    - name: docker.service
      command: start
    - name: nginx.service
      command: start
      content: |
        [Unit]
        Description=nginx
        After=docker.service
        Requires=docker.service

        [Service]
        TimeoutStartSec=0
        ExecStartPre=-/usr/bin/docker kill nginx
        ExecStartPre=-/usr/bin/docker rm nginx
        ExecStartPre=/usr/bin/docker pull nginx
        ExecStart=/usr/bin/docker run --name nginx -p 80:80 -v /etc/nginx/nginx.conf:/etc/nginx/nginx.conf:ro -v /etc/nginx/conf.d:/etc/nginx/conf.d:ro -v /home/core/site:/usr/share/nginx/html:ro nginx
        ExecStop=/usr/bin/docker stop nginx

write_files:
  - path: /var/lib/iptables/rules-save
    permissions: 0644
    owner: 'root:root'
    content: |
      *filter

      :INPUT DROP [0:0]
      :FORWARD DROP [0:0]
      :OUTPUT ACCEPT [0:0]
      :RH-Firewall-1-INPUT - [0:0]

      -A INPUT -j RH-Firewall-1-INPUT
      -A FORWARD -j RH-Firewall-1-INPUT

      -A RH-Firewall-1-INPUT -i lo -j ACCEPT

      -A RH-Firewall-1-INPUT -p icmp --icmp-type echo-reply -j ACCEPT
      -A RH-Firewall-1-INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
      -A RH-Firewall-1-INPUT -p icmp --icmp-type time-exceeded -j ACCEPT

      -A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -m limit --limit 900/min -j ACCEPT

      -A RH-Firewall-1-INPUT -m conntrack --ctstate  ESTABLISHED,RELATED -j ACCEPT

      -A RH-Firewall-1-INPUT -m conntrack --ctstate NEW -m multiport -p tcp --dports xxxx -j ACCEPT

      -A RH-Firewall-1-INPUT -j LOG
      -A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited

      COMMIT

  - path: /var/lib/ip6tables/rules-save
    permissions: 0644
    owner: 'root:root'
    content: |
      *filter

      :INPUT DROP [0:0]
      :FORWARD DROP [0:0]
      :OUTPUT ACCEPT [0:0]
      :RH-Firewall-1-INPUT - [0:0]

      -A INPUT -j RH-Firewall-1-INPUT
      -A FORWARD -j RH-Firewall-1-INPUT

      -A RH-Firewall-1-INPUT -i lo -j ACCEPT

      # Permit needed ICMP packet types for IPv6 per RFC 4890.
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 1   -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 2   -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 3   -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 4   -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 133 -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 134 -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 135 -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 136 -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 137 -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 141 -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 142 -j ACCEPT
      -A RH-Firewall-1-INPUT -s fe80::/10 -p icmpv6 --icmpv6-type 130 -j ACCEPT
      -A RH-Firewall-1-INPUT -s fe80::/10 -p icmpv6 --icmpv6-type 131 -j ACCEPT
      -A RH-Firewall-1-INPUT -s fe80::/10 -p icmpv6 --icmpv6-type 132 -j ACCEPT
      -A RH-Firewall-1-INPUT -s fe80::/10 -p icmpv6 --icmpv6-type 143 -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 148 -j ACCEPT
      -A RH-Firewall-1-INPUT              -p icmpv6 --icmpv6-type 149 -j ACCEPT
      -A RH-Firewall-1-INPUT -s fe80::/10 -p icmpv6 --icmpv6-type 151 -j ACCEPT
      -A RH-Firewall-1-INPUT -s fe80::/10 -p icmpv6 --icmpv6-type 152 -j ACCEPT
      -A RH-Firewall-1-INPUT -s fe80::/10 -p icmpv6 --icmpv6-type 153 -j ACCEPT

      -A RH-Firewall-1-INPUT -p icmpv6 --icmpv6-type 128 -m limit --limit 900/min -j ACCEPT

      -A RH-Firewall-1-INPUT -m conntrack --ctstate  ESTABLISHED,RELATED -j ACCEPT

      -A RH-Firewall-1-INPUT -m conntrack --ctstate NEW -m multiport -p tcp --dports xxxx -j ACCEPT

      -A RH-Firewall-1-INPUT -j LOG
      -A RH-Firewall-1-INPUT -j REJECT --reject-with icmp6-adm-prohibited

      COMMIT

  - path: /etc/ssh/sshd_config
    permissions: 0600
    owner: root:root
    content: |
      # Use most defaults for sshd configuration.
      UsePrivilegeSeparation sandbox
      Subsystem sftp internal-sftp
      ClientAliveInterval 180
      UseDNS no

      PermitRootLogin no
      AllowUsers core
      PasswordAuthentication no
      ChallengeResponseAuthentication no

  - path: /etc/nginx/nginx.conf
    permissions: 0644
    owner: 'root:root'
    content: |
      user  nginx;
      worker_processes  1;

      error_log  /var/log/nginx/error.log warn;
      pid        /var/run/nginx.pid;

      events {
          worker_connections  1024;
      }

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

          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;
          server_tokens   off;

          keepalive_timeout  65;

          gzip  on;

          include /etc/nginx/conf.d/*.conf;
      }

  - path: /etc/nginx/conf.d/blog.f99aq8ove.net.conf
    permissions: 0644
    owner: 'root:root'
    content: |
      server {
          listen       80;
          server_name  blog.f99aq8ove.net;

          #charset koi8-r;
          #access_log  /var/log/nginx/log/host.access.log  main;

          if ($request_uri ~* "/index\.html?$") {
              rewrite (?i)^(.*)index\.html?$ $1 permanent;
          }

          location / {
              root   /usr/share/nginx/html/blog.f99aq8ove.net;
              index  index.html index.htm;
          }

          #error_page  404              /404.html;

          # redirect server error pages to the static page /50x.html
          #
          #error_page   500 502 503 504  /50x.html;
          #location = /50x.html {
          #    root   /usr/share/nginx/html;
          #}

          # deny access to .htaccess files, if Apache's document root
          # concurs with nginx's one
          #
          location ~ /\.ht {
              deny  all;
          }
      }
      server {
          listen        80 default_server;
          server_name   _;
          return 301 $scheme://blog.f99aq8ove.net$request_uri;
      }

  - path: /etc/nginx/conf.d/f99aq8ove.net.conf
    permissions: 0644
    owner: 'root:root'
    content: |
      server {
          listen       80;
          server_name  f99aq8ove.net;

          #charset koi8-r;
          #access_log  /var/log/nginx/log/host.access.log  main;

          if ($request_uri ~* "/index\.html?$") {
              rewrite (?i)^(.*)index\.html?$ $1 permanent;
          }

          location / {
              root   /usr/share/nginx/html/f99aq8ove.net;
              index  index.html index.htm;
          }

          #error_page  404              /404.html;

          # redirect server error pages to the static page /50x.html
          #
          #error_page   500 502 503 504  /50x.html;
          #location = /50x.html {
          #    root   /usr/share/nginx/html;
          #}

          # deny access to .htaccess files, if Apache's document root
          # concurs with nginx's one
          #
          location ~ /\.ht {
              deny  all;
          }
      }

ssh_authorized_keys:
  - <ssh key>

Related Posts