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>