詳細検索

About the environment before writing recipes in Chef-Solo (Vagrantfile, role, node, data_bags)

Avatar
by komi

About the environment before writing recipes in Chef-Solo (Vagrantfile, role, node, data_bags)
Translated from 日本語 • View original

Hello. This is Komiya.
Before I knew it, the first half of the year was over. It seems that Uji Kintoki has become a delicious season.
Anyway, this is a continuation of the previous article. In this article, I will write about the definition of the environment before writing the Chef-Solo recipe.

I think it's faster to take a look at Chef, which explains Chef terminology lightly, or to watch the standard introductory Chef Solo.
Automated infrastructure is on the menu is also in English, but it is easy to understand.
The things I want to do are as follows.
 Write a vagrantfile to create a virtual instance
 Create a chef repository
 Make a chef cookbook
 Define node
 Define role
 Define data_bags
  ★ That's it ★ for this time
 Write a recipe
 Applying a recipe to a node
 Writing serverspec tests
 Run tests in a real environment

Test Configuration:
 chef-solo original admserver: 10.0.0.93
 knife-solo application client webserver: 10.0.0.240
 knife-solo application client dbserver: 10.0.0.241
 All are CentOS 5.8.

  • Define AWS environment variables

Since it is on the AWS VPC, it is defined accordingly
[shell]# cd # vi .ec2 export AWS_ACCESS_KEY_ID=****** export AWS_SECRET_ACCESS_KEY=******* export AWS_KEYPAIR_NAME=xxx-key export AWS_PRIVATE_KEY_PATH=/ root/.ssh/xxx-key # source .ec2[/shell]

・Write a VagrantFile

If you run vagrant init, you can create a vagrantfile, so edit it and
Write the settings to launch the virtual instance on the VPC.

Note
Provisioning Settings (Chef Solo)
  *Since the configuration file writing method may be different from Vagrant 1.1, you need to see the manual for v2.
How to get a shell script to run

[shell]# vagrant init # cp -p Vagrantfile{,.org} # vi Vagrantfile ----------------------- Vagrant.configure("2") do |config| # Common configuration config.vm.box = "dummy"

#---- Create a web server from here config.vm.define :web do |web| web.vm.box = "dummy" web.vm.provider :aws do |aws| aws.access_key_id = ENV['AWS_ACCESS_KEY_ID'] aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] aws.keypair_name = ENV['AWS_KEYPAIR_NAME'] aws.ssh_ private_key_path = ENV['AWS_PRIVATE_KEY_PATH']

#---- VPC-specific configuration ----# aws.private_ip_address = "10.0.0.240" aws.subnet_id = "subnet-80bxxxx9" aws.security_groups = ["sg-6ebxxxx", "sg-fa81xxxx"] #---- VPC-specific configuration so far ----#

aws.ssh_username = "root" aws.ssh_private_key_path = "~/.ssh/komi-test.pem" aws.instance_type = "t1.micro" aws.tags = ["xxx-web03"] aws.region = "ap-northeast-1" aws.ami = " ami-d7bxxxx6" end ## Provisioning configuration #web.vm.provision :chef_solo do |chef| # chef.cookbooks_path = ["cookbooks", "site-cookbooks"] # chef.roles_path = "roles" # chef.add_role("webserver") # chef.data_bags_path = "data_bags" # chef.node_name = " xxx-web03" # chef.log_level = "debug" #end end

#---- Create a DB server from here config.vm.define :d b do |db| db.vm.provider :aws do |aws| aws.access_key_id = ENV['AWS_ACCESS_KEY_ID'] aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] aws.keypair_name = ENV['AWS_KEYPAIR_NAME'] aws.ssh_ username = '"root' #aws.ssh_private_key_path = ENV['AWS_PRIVATE_KEY_PATH']

#---- VPC-specific settings ----# aws.private_ip_address = "10.0.0.241" aws.subnet_id = "subnet-80bxxxx9" aws.security_groups = ["sg-6ebdxxxx", "sg-fa81xxxx"] #---- VPC-specific settings so far ----#

aws.ssh_username = "root" aws.ssh_private_key_path = "/.ssh/komi-test.pem" #aws.ssh_private_key_path = "/.ssh/id_dsa" aws.instance_type = "t1.micro" aws.tags = [" xxx-db03"] aws.region = "ap-northeast-1" aws.ami = "ami-d7bxxxx6" end ## Provisioning configuration #db.vm.provision :chef_solo do |chef| # chef.cookbooks_path = ["cookbooks", "site-cookbooks"] # chef.roles_path = "roles" # chef.add_role("dbserver") # chef.data_bags_path = "data_bags" # chef.json = { # "mysqld" => { # "server_id" => "103" # } # } # chef.node_name = "xxx-db03" # chef.log_level = "debug" #end end end -----------------------[/shell] The provisioning settings have been commented in due to convenience (*).
(*Data_bags key convenience, etc., it doesn't work well unless it's a knife command, etc.)

The following error occurs when the SecurityGroup is written not as an ID, but with a name or a different subnet in the VPC.

[shell][web] -- Security Groups: ["default,nat-test-grp"] There was an error talking to AWS. The error message is shown below:

InvalidParameterCombination => The parameter groupName cannot be used with the parameter subnet

[web] -- Security Groups: ["sg-6815xxxx", "sg-6ebdxxxx"] There was an error talking to AWS. The error message is shown below:

InvalidParameter => Security group sg-6815xxxx and subnet subnet-80bfxxxx belong to different networks.[/shell]

・Minimum settings before AMI conversion

Once started, it stops in the middle, so I will perform the following settings and take the AMI and specify it again.

[shell]# ssh 10.0.0.240 # cd /root/.ssh # vi authorized_keys[/shell] Register the root key for vagrant

sudo permission settings over ssh after login [shell]# visudo #Defaults requiretty[/shell]

Due to the VPC environment in the transition period, I couldn't go outside, curl failed, knife solo prepare didn't work, and chef didn't install.
Set the stg-equivalent chef-solo source to the NAT instance and point the default gateway of the knife solo client to NAT

[shell]# vi /etc/sysconfig/network GATEWAY=10.0.0.93[/shell]

Create an AMI for a node from the AWS Management Console and launch the instance with vagrant again

  • Launch an instance with vagrant

[shell]# vagrant up --provider=aws omitted [db] Waiting for instance to become "ready"... [db] Waiting for SSH to become available... [db] Machine is booted and ready for use! [db] Rsyncing folder: /root/ => /vagrant[/shell]

So far, it seems that multiple VPC instances have been launched well, so
Next, we create a repository, define an environment such as a role, write a recipe, and provision it. provision is to apply a recipe to an instance.

  • Create a new Chef repository
    [shell]# knife solo init chef-repo # tree -L 1 chef-repo chef-repo |-- cookbooks #サードパーティレシピ置き場 |-- data_bags #ユーザ等データ管理機能使用時に使う |-- JSON file storage for nodes #各サーバ (node) |-- roles  #Roleを使うとき用ディレクトリ |-- site-cookbooks #自作レシピ置き場 '-- solo.rb #cookbookのパスなどを設定[/shell]

Move the vagrantfile directly below the chef repository (so that the cookbook path goes through)
[shell]# mv Vagrantfile chef-repo/[/shell]
・Create the necessary cookbook
You can create it with knife cookbook create cookbook-name -o create-directory-path.
[shell]# cd chef-repo # for i in base_setting login-users httpd mysqld munin zabbix ; do knife cookbook create $i -o site-cookbooks; done # tree -L 1 site-cookbooks/munin site-cookbooks/munin |-- CHANGELOG.md |-- README.md |-- attributes #Attributesはtemplateで指定した変数のデフォルト値置き場 |-- definitions |-- files  #定数のみの設定ファイルやパッケージファイル置き場 |-- libraries |-- metadata.rb |-- providers |-- recipes #レシピ置き場 |-- resources '-- templates #変数を用いる設定ファイル置き場[/shell]

  • Create a Role

By defining a role, when applying it to each server (when editing a json file for node),
You don't have to list recipe names or attributes every time, you can define just the Role name
It feels like you define a role such as webserver or dbserver, and list the recipes according to the role within the role. node defines a role.

Template and Attribute can also be defined in role or node.
  template resource and place a configuration file with variables in the templates directory,
  Place a recipe with the default value in the attributes directory and override the unique value with a role or node.
 *If you want to use the information collected by Ohai, you don't need to set a default value in the attributes directory or not have a node or role value.

Define the recipes you plan to write for each roll
[shell]# cd chef-repo/roles # vi webserver.json { "name":"webserver", "chef_type": "role", "json_class":"Chef::Role", "default_attributes":{ "base_setting": { "swappiness": " 30", "tcp_tw_reuse": "0", "tcp_tw_recycle": "0", "tcp_fin_timeout": "60", "tcp_max_syn_backlog": "4096", "somaxconn": "4096" } }, "override_attributes":{}, "description": "webserver's role", "run_list": [ "recipe[base_setting::bkup_dir]", "recipe[login_users]", "recipe[base_setting::hosts]", "recipe[base_setting::sysctl]", " recipe[base_setting::disable]", "recipe[base_setting::ntpdate]", "recipe[base_setting::mail-client]", "recipe[base_setting::logrotate]", "recipe[httpd:: httpd-server]", "recipe[httpd::basic_auth]", "recipe[httpd::wordpress]", "recipe[httpd::s3mount]", "recipe[munin::munin-node]", "recipe[munin::munin-node-web]" , "recipe[zabbix::zabbix-agent]" ] }

# vi dbserver.json { "name":"dbserver", "json_class":"Chef::Role", "chef_type": "role", "description":"", "default_attributes":{ "base_setting": { "swappiness": "0", "tcp_tw_ reuse": "1", "tcp_tw_recycle": "1", "tcp_fin_timeout": "10", "tcp_max_syn_backlog": "8192", "somaxconn": "8192" } }, "override_attributes":{}, "run_list": [ "recipe[base_ setting::bkup_dir]", "recipe[login_users]", "recipe[base_setting::hosts]", "recipe[base_setting::sysctl]", "recipe[base_setting::disable]", "recipe[base_ setting::ntpdate]", "recipe[base_setting::mail-client]", "recipe[base_setting::logrotate]", "recipe[mysqld::mysqld-server]", "recipe[mysqld::mysql-users]", " recipe[munin::munin-node]", "recipe[munin::munin-node-db]", "recipe[zabbix::zabbix-agent]" ] }

# vi admserver.json { "name":"admserver", "json_class":"Chef::Role", "description":"", "chef_type": "role", "default_attributes":{ "base_setting": { "swappiness": "0", "tcp_ tw_reuse": "0", "tcp_tw_recycle": "0", "tcp_fin_timeout": "60", "tcp_max_syn_backlog": "8192", "somaxconn": "8192" } }, "override_attributes":{}, "run_list": [ "recipe[ base_setting::bkup_dir]", "recipe[login_users]", "recipe[base_setting::hosts]", "recipe[base_setting::sysctl]", "recipe[base_setting::disable]", "recipe[ base_setting::ntpd]", "recipe[base_setting::ntpdate]", "recipe[base_setting::mail-postfix]", "recipe[base_setting::mail-dovecot]", "recipe[base_setting:: logrotate]", "recipe[httpd::httpd-server]", "recipe[httpd::wordpress]", "recipe[mysqld::mysqld-server]", "recipe[mysqld::mysql-users]", "recipe[munin::munin-node\ ]", "recipe[munin::munin-node-web]", "recipe[munin::munin-node-db]", "recipe[munin::munin-server]", "recipe[zabbix::zabbix-agent]", "recipe[zabbix::zabbix-proxy] " ] }[/shell]
*According to the beginner Chef anti-pattern, role cannot be versioned.
 It seems that the runlist should not be managed by role (subject to refactoring)

*I wanted sysctl.conf to have a different value for each role, so I decided to override it by embedding a variable in the template and using an attribute.
I will explain template and attribute in detail next time, but understand the [[chef] attribute. (http://tech.blog.piyo.org/2012/05/23/chef-attribute%E3%81%AE%E7%90%86%E8%A7%A3/) was easy to understand.
I'm sorry that this is a story that has nothing to do with chef, but as it is written here,
You should (in some cases) stop enabling "net.ipv4.tcp_tw_recycle".
Using the same line from a public wireless LAN environment with a smartphone, etc.
Communication may not be possible when accessing from multiple different terminals at the same time.
In other words, 0 is the recommended value for the front WEB and MTA server.
If it is a backend DB that should always be connected from a different IP, there should be no problem with 1. Maybe.

・Create a JSON file for node
[shell]# cd chef-repo/nodes # vi localhost.json { "run_list":[ "role[admserver]" ] }

# vi 10.0.0.240.json { "run_list":[ "role[webserver]" ] }

# vi 10.0.0.241.json { "mysqld" : { "server_id" : 103 }, "run_list":[ "role[dbserver]" ] }[/shell]

*Role and recipe can be written together.
*If you don't use role, you have to write everything in node, so if you have 30 web servers, it's rather troublesome.
*Specifies the attribute of the server_id parameter of MySQL that needs to be separated for each node.
*If you want to provision with vagrant, you may not need much of the node JSON file.

・Prepare user management with data_bags

data_bags is something that can be managed such as data search with LDAP-like functions.
If you use chef-server, you can communicate with the server to retrieve data and reflect it.
Since this is Chef-solo, we will prepare data in a local file and reflect it.

Reference:
If you have a large number of users and frequently add and change accounts, it would be a good idea to use data_bags to manage the enablement and disabling as shown in the link below.
How to use chef-data-bag

[shell]# cd ; cd chef-repo/data_bags # mkdir users; cd users # vi xxx-op.json // xxx-op.json { "id" : "xxx-op", "groups": [ "xxx-op","wheel" ], "uid": 1000, "username" : "xxx-op", "home" : "/home/xxx-op", "shell" : "/bin/bash", "password" : "$1$ Ka.Mw69U$TT5HRfSe7xxxxx" }

# vi yyy-op.json // yyy-op.json { "id" : "yyy-op", "groups": [ "yyy-op","wheel" ], "uid": 500, "username" : "yyy-op", "home" : "/home/yyy-op", "shell" : "/bin/bash", "password" : "$1$Ka. Mw69U$TT5HRfSe78Pxxxxx" }

# vi dev.json // dev.json { "id" : "dev", "groups": [ "dev","wheel" ], "uid": 501, "username" : "dev", "home" : "\/home\/dev", "shell" : "\/bin\/bash", "password" : "$1$S/q25RbR$ oO7pCoAjBWxxxxx" }[/shell]

Create a password with the following command
[shell]# openssl passwd -1[/shell]

[shell]# knife solo data bag show users[/shell] Make sure the data is displayed

  • Encrypt the user definition in MySQL

*Defining passwords in plain text in JSON files for nodes and roles is not secure, and it is not smart to record them for each node.
 So let's use databags that can be encrypted using keys
 It seems that encryption cannot be used with only knife-solo, but if you _bag gem install knife-solo_data\, you will be able to use it.

[shell]# openssl rand -base64 512 | tr -d '\r\n' > /etc/chef/encrypted_data_bag_secret # chmod 400 encrypted_data_bag_secret # cd /root/chef-repo # knife solo data bag create mysqlusers root --secret-file ./ encrypted_data_bag_secret The editor will open, enter the following { "id": "root", "user": "root", "pass": "xxxxxxx", "host": "localhost", "privileges": "all" }

# knife solo data bag create mysqlusers repl --secret-file ./encrypted_data_bag_secret The editor will open, enter the following { "id": "repl", "user": "repl", "pass":"xxxxxxx", "host":"10.0.0.%", " privileges": ["\\:replication slave", "\\:replication client"] }

# knife solo data bag create mysqlusers xxx_admin --secret-file ./encrypted_data_bag_secret The editor will open, enter the following { "id": "xxx_admin", "user": "xxx_admin", "pass": "xxxxxxx", "host": "10.0.0.%" "privileges": "all" }

# knife solo data bag create mysqlusers zabbix --secret-file ./encrypted_data_bag_secret The editor will open, enter the following { "id": "zabbix", "user": "zabbix", "pass": "xxxxxxx", "host": "localhost", "privileges": "all" }

Confirm # knife solo data bag show mysqlusers # knife solo data bag show mysqlusers repl --secret-file ./encrypted_data_bag_secret # knife solo data bag show mysqlusers root --secret-file . /encrypted_data_bag_secret # knife solo data bag show mysqlusers xxx_admin --secret-file ./encrypted_data_bag_secret # knife solo data bag show mysqlusers zabbix --secret-file . /encrypted_data_bag_secret[/shell] data is displayed
Other commands can be found below.
[shell]# knife solo data bag --help[/shell]
It seems that it is possible to pass the key for databags to the client host in a bootstrap file with chef-server,
Perhaps because of knife-solo_data_bag, it seemed that there was no need to specify the bootstrap file when using knife solo cook hostname.
I don't really know how to do it on the vagrant side.

I will post a recipe on how to call it from the recipe later, but the following will be helpful.
Reference:
Records of using DataBags to encrypt JSON data that you don't want to publish in Chef Handling MySQL passwords in Chef
It seems that Chef-Server can separate the production environment and the test environment by environment, but it is a little disappointing that this function is not included in Chef-Solo.
In the case of a slightly larger environment (more than 20 units), Chef-Server seems to be better, so if there is such a story, I may use it、、、
I thought so, but once I searched, it seems to be available from 11.6. Oh, I'm happy. I'll try to save it later.

That's it for this time. Thank you for watching.
The next step is about the recipe.

Related Articles