Nginxã¸ã®å¤æ´ã«ä¼´ããªãã¼ã¹ãããã·ã®ãã¹ãã®æ¹å
SREã°ã«ã¼ãã®è åã§ãã ã¯ãã¯ãããã§ã¯ãã©ã¦ã¶ç¨Webãµã¤ãã®ãªãã¼ã¹ãããã·ç¨ã®Webãµã¼ãã¨ãã¦é·ããApacheã使ã£ã¦ããã®ã§ãããæè¿ãNginxã¸ã¨å¤æ´ãã¾ããã
Nginxã¸ã®å¤æ´ã«å½ãã£ã¦ãæ§æ管çã®å¤æ´ããã¹ãã®æ¹åãè¡ã£ãã®ã§ããããã«ã¤ãã¦æ¸ãããã¨æãã¾ãã
ãªãã¼ã¹ãããã·ã®ãªãã¥ã¼ã¢ã«ã«ã¤ãã¦
ã¾ãããã©ã¦ã¶ç¨Webãµã¤ãã®åºæ¬çãªãµã¼ãæ§æã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
ãªãã¼ã¹ãããã·ã¯ELBçµç±ã§ãªã¯ã¨ã¹ããåãã¦ãéçãã¡ã¤ã«ã®é ä¿¡ããã£ãã·ã¥ãµã¼ãã»Appãµã¼ãã¸ã®æ¯ãåããè¡ãã¾ãã
ãªãã¼ã¹ãããã·ã¨ãã¦å©ç¨ããã¦ããApacheã¯ãé·å¹´ã®æ¹ä¿®ã«ããè¨å®ãç ©éãªãã®ã¨ãªã£ã¦ãããè¨å®ã®è¿½å ãå¤æ´ã«ã³ã¹ãããããç¶æ ã«ãªã£ã¦ãã¾ããã
ã¾ããApacheã®è¨å®ãã¡ã¤ã«ã¯Itamaeã§ã¯ç®¡çããã¦ããããItamaeã®ã¬ã·ããããGitãªãã¸ããªã¨ã¯å¥ã«ãApacheã®è¨å®ãã¡ã¤ã«ã ããæ ¼ç´ããGitãªãã¸ããªã§ç®¡çãããCapistranoã§è¨å®ãé å¸ããæ¹å¼ã«ãªã£ã¦ãã¾ãããããã¯å½åããµã¼ãå ¨ä½ã®æ§æ管çï¼å½æã¯Puppetï¼ã®é©ç¨ã¿ã¤ãã³ã°ã¨ããããã·ãµã¼ãã®è¨å®ã®å¤æ´ã¿ã¤ãã³ã°ãç°ãªãã¨èãã¦ã®ãã¨ã ã£ãã®ã§ãããç¾ç¶ã§ã¯åã«ç®¡çãè¤éã«ãªãã ãã§ã¡ãªããããªãç¶æ ã«ãªã£ã¦ãã¾ããã
ãã®ç¶æ³ãè¸ã¾ãããªãã¼ã¹ãããã·ã®OSãªã©ã®ãªãã¥ã¼ã¢ã«ãããã¿ã¤ãã³ã°ã§ãããå¹³æã«è¨å®ãæ¸ããã¨ãã§ããNginxã¸å¤æ´ããã¾ããNginxã®è¨å®ãã¡ã¤ã«ã«ã¤ãã¦ã¯Itamaeã®ç®¡çä¸ã«ç½®ããã¨ã«ãã¾ããã
æ¢åã®ãªãã¼ã¹ãããã·ã®ãã¹ãã«ã¤ãã¦
以åã®è¨äºã§ãåãä¸ããããã®ã§ããããªãã¼ã¹ãããã·ã®è¨å®ã¯Infratasterã§ãã¹ããè¡ããã¦ãã¾ãã
Infratasterã®ãã¹ãã«ã¯Docker Composeã使ç¨ãã¦ããã以ä¸ã®ãããªã³ã³ããã®æ§æã«ãªã£ã¦ãã¾ããã
åè¿°ã®éããApacheã®è¨å®ã¯Itamaeã¨ã¯å¥ã®Gitãªãã¸ããªã§ç®¡çããã¦ãããcookpad.comãå«ã主è¦ãªãµã¼ãã¹ã®è¨å®ãåããªãã¸ããªã«å«ã¾ãã¦ãã¾ãã
[ãªãã¼ã¹ãããã·ãªãã¸ããª] âââ cookpad/ â âââ conf/ â â âââ httpd.conf â âââ conf.d/ â âââ xxx.conf âââ other_service_a/ â âââ conf/ â â âââ httpd.conf â âââ conf.d/ â âââ xxx.conf âââ other_service_b/ â âââ conf/ â â âââ httpd.conf â âââ conf.d/ â âââ xxx.conf âââ spec/ âââ cookpad_spec.rb âââ other_service_a_spec.rb âââ other_service_b_spec.rb âââ docker/  â âââ apache/ â â âââ Dockerfile â âââ backend â â âââ Dockerfile â âââ taster/ â âââ Dockerfile  âââ docker-compose.yml
ãã¹ãç¨ã®docker-compose.ymlã§ã¯ãcookpad.comãå«ããµã¼ãã¹æ¯ã®ã³ã³ããããè¨å®ãã¡ã¤ã«ã®ãã£ã¬ã¯ããªããã¦ã³ãããå½¢ã§èµ·åããInfratasterããRSpecãå®è¡ããããã«ãªã£ã¦ãã¾ãã
ãªãã¼ã¹ãããã·ããããã¼ããã¯ã¨ã³ãã«ã¢ã¯ã»ã¹ããå ´åã¯ãDocker Composeã®link_local_ipsè¨å®ã使ã£ã¦ããã¼ããã¯ã¨ã³ãã®ã³ã³ããã«IPã¢ãã¬ã¹ãå²ãå½ã¦ããªãã¼ã¹ãããã·ã®/etc/hosts
ãæ¸ãæãããã¨ã§ããªãã¼ã¹ãããã·ããããã¯ã¨ã³ãã¸ã®åãåããããããã¼ããã¯ã¨ã³ãã«å·®ãæ¿ããããã«ãã¦ãã¾ããã*1
# docker-compose.yml backend: networks: bridge: link_local_ips: - 169.254.100.100 - 169.254.100.101 - 169.254.100.102 ...
ã
# /etc/hosts 169.254.100.100 app-server-001 169.254.100.101 cache-server-001 169.254.100.102 ad-server-001 ...
ã³ã³ããã¸ã®Itamaeã®é©ç¨
Itamae管çä¸ã«ç½®ãããNginxã®è¨å®ãã¡ã¤ã«ããã¹ãããã«ã¯ãæ¢åã®æ¹å¼ã®ããã«ãã£ã¬ã¯ããªããã¦ã³ãããã®ã§ã¯ãªããã³ã³ããã«å¯¾ãã¦Itamaeãé©ç¨ããå¿ è¦ãããã¾ãã
Itamaeã¬ã·ãã®Gitãªãã¸ããªã¯ãã ããã以ä¸ã®ãããªãã¡ã¤ã«æ§æã«ãªã£ã¦ãã¾ãã
[Itamaeãªãã¸ããª] âââ ... âââ itamae/ âââ function.rb âââ cookbooks/ â âââ nginx/ â âââ default.rb â âââ files/ â âââ templates/ âââ roles/ âââ apne1_vpc-xxx/ âââ rproxy/ âââ default.rb âââ td-agent.rb âââ files/ âââ templates/
ãããCapistranoã使ã£ã¦ãé©ç¨å¯¾è±¡ã®ãµã¼ãä¸ã§itamae local function.rb roles/apne1_vpc-xxx/default.rb
ã¨ãããããªã³ãã³ããå®è¡ãã¦ãã¬ã·ããé©ç¨ãã¾ãã
function.rbã¯Itamaeã®ãã«ãã¼ãå®ç¾©ããã¦ãã
module RecipeHelper def include_role(name) include_role_or_cookbook(name, "role") end def include_cookbook(name) include_role_or_cookbook(name, "cookbook") end def include_role_or_cookbook(name, type) Pathname.new(File.dirname(@recipe.path)).ascend do |dir| names = name.split("::") names << "default" if names.length == 1 if type == "cookbook" recipe_file = dir.join("cookbooks", *names) else recipe_file = dir.join(*names) end if recipe_file.exist? include_recipe(recipe_file.to_s) return end end raise "#{name} is not found." end end Itamae::Recipe::EvalContext.send(:include, RecipeHelper)
Itamaeã®ã¬ã·ãå ã§
include_cookbook 'nginx' include_recipe 'rproxy::td-agent'
ã¨æ¸ããã¨ã«ãããroles/
ãcookbooks/
é
ä¸ã®ã¬ã·ããèªã¿è¾¼ããããã«ãã¦ãã¾ããã
ãããã®Itamaeã®ã¬ã·ããã³ã³ããã«é©ç¨ããå ´åã以ä¸ã®åé¡ç¹ãããã¾ãã
- Nodeãªãã¸ã§ã¯ãã«å«ã¾ãããµã¼ãã®ã¡ã¿æ
å ±ï¼ä¾:
node[:ec2]
ï¼ããã³ã³ããé©ç¨æã«ã¯å«ã¾ããªã - Nginx以å¤ã®ä¸è¦ãªã¬ã·ãï¼ä¾:
zabbix-agent
ãªã©ï¼ãé©ç¨ããã¦ãã¾ã
1
ã®åé¡ã«ã¤ãã¦ã¯ãNodeã¯ã©ã¹ãæ¸ãæãããã¨ã«ãã£ã¦åé¿ãã¾ããã
以ä¸ã®ã³ã¼ããItamaeé©ç¨æã«èªã¿è¾¼ã¾ãããã¨ã§ãã¬ã·ãããEC2ã®ã¡ã¿æ
å ±ãªã©ãåç
§ããå ´åã«ãæªå®ç¾©ã®ã¨ãã¯nil
ãè¿ãã®ã§ã¯ãªããããã¼å¤ï¼key
ï¼ãè¿ãããã«ãã¦ãã¬ã·ãã®é©ç¨ã失æããªãããã«ãã¾ããã
module FakeNode module Value def [](key) key.to_s end alias :fetch :[] end def [](key) value = super if value.nil? && !self.mash.has_key?(key) case key when :http_proxy nil when :rspec true else key.to_s.tap do |v| v.extend(Value) end end else value end end end Itamae::Node.prepend FakeNode
ã¾ãã2
ã®åé¡ã«ã¤ãã¦ã¯ãSKIP_RECIPES
ã¨ããç°å¢å¤æ°ãå®ç¾©ãã¦ãããã«å«ã¾ããã¬ã·ãã¯Itamaeã§ã¯é©ç¨ããªãããã«ãã«ãã¼ãä¿®æ£ãã¾ããã
module RecipeHelper SKIP_RECIPES = ENV.fetch('SKIP_RECIPES', '').split(',') def include_role_or_cookbook(name, type) return if SKIP_RECIPES.include?(name)
ä¸è¨ã®ä¿®æ£ãªã©ã«ãããæ¢åã®Itamaeã¬ã·ãã«å¤§ããªä¿®æ£ããããã¨ãªãããµã¼ãåæ§ã«ã³ã³ããã«ãItamaeãé©ç¨ã§ããããã«ãªãã¾ããã
Dockerfileã§ã®Itamaeãé©ç¨ããç®æã¯ä»¥ä¸ã®ãããªã³ã¼ãã«ãªãã¾ãã
ENV SKIP_RECIPES haproxy,td-agent,zabbix-agent RUN cd /infra2 && \ itamae local \ spec/itamae/fake_node.rb \ itamae/functions.rb \ itamae/roles/apne_vpc-xxx/rproxy/default.rb
ãã¹ãã®æ¹å
æ¢åã®ãªãã¼ã¹ãããã·ã®ãã¹ããItamaeãªãã¸ããªã«ç§»è¡ããã«å½ãã£ã¦ã以ä¸ã®ç¹ãæ¹åããããã«ãã¾ããã
- è¤æ°ã®ãµã¼ãã¹ãåãdocker-compose.ymlã§å®ç¾©ããã®ãããã¦ãç°å¢æ§ç¯ã®æéãç縮ãããã¹ãã®ç¸äºä¾åããªãã
link_local_ips
ã¨/etc/hosts
ã使ã£ãçµè·¯ã®å·®ãæ¿ãããããã¨ã³ããã¤ã³ãã®ãã¹ãåãã®ã¾ã¾ã§ããã¼ãµã¼ãã«ã¢ã¯ã»ã¹ã§ããããã«ãã- å®éã®ãµã¼ãæ§æãåç¾ããããã«ã³ã³ãããæ§æãã¦ãSSL TerminationãIPã®å½è£ ãªã©ã®å¦çããªãã¼ã¹ãããã·ã®ã³ã³ããã«æã¡è¾¼ã¾ãªã
æçµçã«ãã¹ãã¾ããã®ã³ã³ããæ§æã»ãã¡ã¤ã«æ§æã¯ä»¥ä¸ã®ããã«ãªãã¾ããã
[itamae/spec] âââ backend/ â âââ Dockerfile â âââ files/ â âââ backend.rb â âââ init.sh âââ internal_service_proxy/ â âââ Dockerfile â âââ files/etc/nginx/conf.d/default.conf.tmpl âââ itamae/ â âââ fake_node.rb âââ rproxy/ â âââ Dockerfile â âââ docker-compose.yml â âââ files/ â â âââ etc/haproxy/haproxy.cfg â â âââ init.sh â âââ spec/ â âââ cookpad_spec.rb â âââ spec_helper.rb âââ ssl/ â âââ cookpad.com.crt â âââ cookpad.com.key â âââ root-ca.crt âââ taster/ âââ Dockerfile
ã¾ãdocker-compose.ymlã¯ä»¥ä¸ã®ããã«ãªãã¾ããã
version: '3' services: backend: build: context: ../backend networks: - spec-network internal-service: environment: SERVERS: cache-server-001:backend build: context: ../internal_service_proxy depends_on: - backend networks: spec-network: aliases: - cache-server-001 rproxy: build: context: ../.. dockerfile: spec/rproxy/Dockerfile depends_on: - backend - internal-service networks: - spec-network elb: environment: SERVERS: cookpad.com:rproxy build: context: ../ssl_termination_proxy volumes: - ../ssl:/ssl depends_on: - rproxy networks: spec-network: aliases: - cookpad.com taster: build: context: ../.. dockerfile: spec/taster/Dockerfile volumes: - ./spec:/spec working_dir: /spec depends_on: - elb networks: - spec-network networks: spec-network:
elbã³ã³ããï¼ssl_termination_proxy/
ï¼
elbã³ã³ããã¯ãSSL Terminationãè¡ãã³ã³ããã§ãELBã®å½¹å²ãæ ãã³ã³ããã§ãã Docker Composeã®aliasesãå©ç¨ãã¦ãå®éã¨åæ§ã®ãã¹ãåã§ã³ã³ããã«ã¢ã¯ã»ã¹ã§ããããã«ãã¦ãã¾ãã
ã³ã³ããã§åãNginxã®è¨å®ã«ã¯ã以ä¸ã®ããã«ãã³ãã¬ã¼ããç¨æãã¦*2
{{ range $server_name, $backend := var "SERVERS" | split "," | splitkv ":" }} server { listen 80; listen 443 ssl; server_name {{ $server_name }}; ssl_certificate /ssl/{{ $server_name }}.crt; ssl_certificate_key /ssl/{{ $server_name }}.key; underscores_in_headers on; location / { # set external network ip address set $custom_x_forwarded_for "93.184.216.34"; if ($http_x_test_client_ip != "") { set $custom_x_forwarded_for $http_x_test_client_ip; } proxy_set_header X-Forwarded-Host $host:$server_port; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $custom_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://{{ $backend }}; } } {{ end }}
ç°å¢å¤æ°SERVERS
ã®å¤ï¼ãã¹ãå:ããã¯ã¨ã³ã,...
ï¼ã§åãµã¼ãã¹ã®server
ã¨proxy_pass
ãå®ç¾©ããã¾ãããã¹ãåæ¯ã«ããããããç¨æãã¦ãããSSL証ææ¸ãèªã¿è¾¼ãããã«ãã¦ãhttpsã§ãã¢ã¯ã»ã¹ã§ããããã«ãã¦ãã¾ãã
ï¼ã«ã¼ã証ææ¸ã¯tasterã³ã³ããã«å«ãã¦ãã¾ãï¼
ã¾ããã¯ã©ã¤ã¢ã³ãããã®ãªã¯ã¨ã¹ãã«X-Test-Client-IP
ã¨ããããããã¤ãããã¨ã§ãä»»æã®IPãããªãã¼ã¹ãããã·ã«ãªã¯ã¨ã¹ããæããããããã«è¦ããããããã«ããã¦ãã¾ãã
ãã®æ©è½ã®ãããngx_http_realip_module
ãèªã¿è¾¼ãç®æã®Itamaeã¬ã·ãã§ã¯ããã¹ãç¨ã³ã³ããã¸ã®é©ç¨æã«set_real_ip_fromã®ã¬ã³ã¸ãåºããããã«ãã¦ãã¾ãã
real_ip_header X-Forwarded-For; set_real_ip_from xx.xx.xx.xx/xx; <%- if node[:rspec] -%> set_real_ip_from 0.0.0.0/0; <%- end -%> real_ip_recursive on;
rproxyã³ã³ããï¼rproxy/
ï¼
rproxyã³ã³ããã¯ããã¹ã対象ã¨ãªããªãã¼ã¹ãããã·ã®ã³ã³ããã§ããåè¿°ã®Itamaeã¬ã·ãã®é©ç¨ãè¡ã£ãNginxãµã¼ããåä½ãã¾ãã cookpad.comç¨ã®docker-compose.ymlã¯ãã®ãã£ã¬ã¯ããªã«ç½®ãã¦ãcookpad.comé¢é£ä»¥å¤ã®ã³ã³ããã®å®ç¾©ãå«ã¾ããªãããã«ãã¾ããã
rproxyã³ã³ããã®Nginxã®è¨å®ã¯Itamaeã¬ã·ãã§é©ç¨ããããããå®éã®ãµã¼ãã¨åãã§ãããHAProxyã®è¨å®ã ãã¯Itamaeã¬ã·ãã®ãã®ã使ããã«ããã¹ãå°ç¨ã«ç¨æãã¦ãã¾ãã
listen www bind :8080 mode http balance roundrobin http-request set-header X-Via-Haproxy 'localhost:www:8080' server app-server-001 backend:80 check inter 5s fall 3
ãã®è¨å®ã«ãããlocalhost:8080ã¸ã®ã¢ã¯ã»ã¹ã¯backendã³ã³ããã«æããããããã«ãªãã¾ãã
internal-serviceã³ã³ããï¼internal_service_proxy
ï¼
internal-serviceã³ã³ããã¯ãHAProxyãçµç±ããªããã£ãã·ã¥ãµã¼ãã¸ã®ãªã¯ã¨ã¹ããåãä»ããã³ã³ããã§ããåºæ¬çã«ã¯elbã³ã³ããã¨åããããªæ§æã§ãSSL Terminationã®æ©è½ãé¤ããã¦ãã¾ãã
Nginxã®è¨å®ã¯ä»¥ä¸ã®ãããªãã³ãã¬ã¼ãã§ãelbã³ã³ããã¨åæ§ã«ç°å¢å¤æ° SERVERS
ã§server
ã¨proxy_pass
ãå®ç¾©ãã¦ãã¾ãã
{{ range $server_name, $backend := var "SERVERS" | split "," | splitkv ":" }} server { listen 80; server_name {{ $server_name }}; location / { set $custom_x_forwarded_for $proxy_add_x_forwarded_for; if ($http_x_test_client_ip) { set $custom_x_forwarded_for $http_x_test_client_ip; } proxy_set_header X-Dest {{ $server_name }}; proxy_pass http://{{ $backend }}; } } {{ end }}
ã¾ããaliasesè¨å®ã使ã£ã¦ããããã¯ã·ã§ã³ãµã¼ãã®ãã¹ãåãã®ã¾ã¾ã§ãinternal-serviceã³ã³ããã«ã¢ã¯ã»ã¹ã§ããããã«ãã¦ãã¾ã
backendã³ã³ããï¼backend/
ï¼
backendã³ã³ããã¯ãå種ãµã¼ããå½è£ ããããã¼ãµã¼ãã§ãWebrickã§æ¸ãã¦ãã¾ãã
#!/usr/bin/env ruby require 'webrick' require 'json' require 'mime/types' URI_ATTRS = %w( scheme userinfo host port registry path opaque query fragment ) server = WEBrick::HTTPServer.new(Port: 80) trap(:INT){ server.shutdown } server.mount_proc('/') do |req, res| uri = req.request_uri res.body = JSON.pretty_generate({ request_method: req.request_method, uri: URI_ATTRS.map {|k| [k, uri.send(k)] }.to_h, header: req.header, body: req.body, }) res.keep_alive = false mime_type = MIME::Types.type_for(uri.path).first res.content_type = mime_type.to_s if mime_type x_test_set_cookie = req['x-test-set-cookie'] res['set-cookie'] = x_test_set_cookie if x_test_set_cookie x_test_status = req['x-test-status'] res.status = x_test_status.to_i if x_test_status end server.start
åºæ¬çã«ãªã¯ã¨ã¹ãã®æ
å ±ãJSONã§è¿ãã ãã®ãµã¼ãã§ãããX-Test-...
ã¨ãããªã¯ã¨ã¹ãããããæ¥ãå ´åã«ãä»»æã®Cookieãã¹ãã¼ã¿ã¹ã³ã¼ããè¿ããããã«ãã¦ãç°å¸¸ç³»ãªã©ã®ãã¹ããã¿ã¼ã³ã«å¯¾å¿ãã¦ãã¾ãã
tasterã³ã³ããï¼taster/
ï¼
tasterã³ã³ããã¯ãInfratasterãå®è¡ããã³ã³ããã§ãã
Infratasterã¨ãrproxy/
é
ä¸ã®specãå«ãããã«ãã¦ãã¾ãã
RSpec
ãªãã¼ã¹ãããã·ããã¹ãããããã®specãã¡ã¤ã«ã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
# spec_helper.rb require 'infrataster/rspec' %w( cookpad.com xxx.cookpad.com ).each do |server| Infrataster::Server.define(server, server) RSpec.shared_examples "#{server} normal response" do it 'returns 200' do expect(response.status).to eq(200) end it "accesses #{server}" do expect(request_uri.fetch('host')).to eq(server) end end end
ã
# cookpad_spec.rb describe server('cookpad.com') do let(:body_as_json) { JSON.parse(response.body) } let(:request_uri) { body_as_json.fetch('uri') } describe 'normal' do describe http('https://cookpad.com') do it_behaves_like 'cookpad.com normal response' it_behaves_like 'https' it "doesn't cache" do expect(response.headers).not_to have_key('cache-control') end end end describe 'error pages' do describe http('https://cookpad.com/error', headers: {'X-Test-Status' => 500}) do it "return front 500 page" do expect(response.status).to eq(500) expect(response.body.strip).to eq("fw_errors/500.html") end end end end
aliasesè¨å®ã使ã£ããã¨ã§ãã³ã³ããã®IPãªã©ãæèãããã¨ãªããã¹ããè¨è¿°ãããã¨ãã§ãã¾ãã
RSpecã¯docker-composeãã¤ãã£ã¦ä»¥ä¸ã®ããã«å®è¡ãã¾ãã
docker-compose run taster rspec -I. -r spec_helper .
ã¾ã¨ã
ä»åã®ä½æ¥ã«ãããç ©éã ã£ãè¨å®ãã¡ã¤ã«ã®è¦éãããããªããè¨å®ã®è¿½å ãªã©ã大å楽ã«ãªãã¾ããã ã¾ãããã¹ãã¾ããã®æ¹åããããã¨ã§ããã¹ãç°å¢ã®æ§ç¯ã«æéãããã£ãããåå ä¸æã§ãã¹ããã³ã±ããããªãã¨ããªããªãããã¹ãã«ä»éããyak shavingãæ¸ããã¾ããã 以åã®ãè¨å®ãå¤æ´ããâãã¹ããããã©ãããâãã¹ãããµãã/è¨å®ã®è¿½å ã諦ãããã¨ãããããªè² ã®ã¹ãã¤ã©ã«ããã¾ãæã¡åããæ°ããã¾ãã
ã¡ãã£ã¨å®è¡ãããã¹ãã®çµæãFFFFFFFFFFFFFFF...ã«ãªã£ã¦ããã¨ãç²¾ç¥ã«å¤§å¤ãªãã¡ã¼ã¸ãåããã®ã§ãæªæ¥ã®èªåã®ã¡ã³ã¿ã«ãã«ã¹ãä¿ã¤ããã«ãä»å¾ãæ¹åãç¶ãã¦ããããã¨ããã§ãã