Sei sulla pagina 1di 46

1

Using Automation Tools to Provision


and Manage OCI Resources
April 2018
v2.0

Copyright © 2018, Oracle and/or its affiliates. All rights reserved.


Module 3: Overview

In this module you will learn how to leverage tools like Terraform, the OCI Command Line
Interface (CLI), Chef, and the OCI Software Development Kit (SDK) to automate common
tasks. We will discuss the concept of Infrastructure as Code and how Terraform can be
used to provision a complete set of OCI resources.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1-2
Module 3: Goals and Objectives

• Describe key features and functionality of Terraform, CLI, Chef, and the OCI SDK
• Describe the core components of Terraform: providers, resources, and variables
• Compare and contrast Terraform against other, agentless provisioning tools
• Use the CLI to create, discover, and terminate resources
• Use Terraform with the OCI provider to provision a VCN and Compute resource

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1-3
Hands-on Labs

During this module you will be completing two hands-on exercises.

1. Getting started with the OCI Command Line Interface (30 minutes)
2. Getting started with Terraform (60 minutes)

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1-4
Automation Concepts and Tools

Infrastructure as Code
• Ad-hoc scripts such as PowerShell or Bash (OCI Command Line Interface)
• Configuration Management Tools (Chef, Puppet, Ansible)
• Server templating tools (Packer, Vagrant, Docker)
• Infrastructure Automation Tools (Terraform, Heat, CloudFormation)

Infrastructure Lifecycle
• Provision
• Update
• Destroy

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1-5
OCI Software Development Kits (SDK)

The OCI Software Development Kits enable you


to programmatically interact with your Oracle
Cloud Infrastructure. Consider the following
scenarios: Sample Python Code
>>> import oci
• You have built an application that accepts >>> config = oci.config.from_file(
customer uploads and stores their files ... "~/.oci/config",
... "integ-beta-profile")
durably in object storage. Using the SDK you >>> identity = oci.identity.IdentityClient(config)
could design your application to interact >>> user = identity.get_user(config["user"]).data
>>> print(user)
directly with Object Storage Service. {
"compartment_id": "ocid1.tenancy.oc1...",
• You are leveraging an open source "description": "Integration testing user [BETA]",
monitoring tool and would like to extend its "id": "ocid1.user.oc1...",
functionality. You could write custom code to "inactive_status": null,
"lifecycle_state": "ACTIVE",
evaluate or even alter running resources. "name": "testing+integ-beta@corp.com",
"time_created": "2016-08-30T23:46:44.680000+00:00"
}

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1-6
OCI Software Development Kits (SDK) - continued

The following languages are currently supported:


• Java
• Python
• Ruby

Sample: List buckets in object storage service (Python)

object_storage_client = oci.object_storage.ObjectStorageClient(config={},
signer=signer)
print(object_storage_client.get_namespace().data)
print(object_storage_client.list_buckets(namespace_name=object_storage_client
.get_namespace().data, compartment_id=compartment_id).data)

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1-7
Overview of the CLI

The CLI is an essential tool for managing your OCI resources. It provides much of the same
functionality found in the console, and extended functionality through the use of scripts.

Key Features
• Built with the Python SDK
• Compatible with Python 2.7.5+ or 3.5+
• Compatible with Mac, Windows, and Linux
• Direct OCI API interaction

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1-8
CLI Command Construct

The OCI CLI is a unified tool that allows interaction with most service through a single
command. After entering the program command specify the service, the action, and any
additional switches.

service component command parameters


name action

$ oci compute instance list --region us-phoenix-1 --availability-domain gKOA:PHX-AD-1 --limit 2 --sort-by TIMECREATED

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1-9
Installing the CLI

The CLI can either be installed using a script, or it can be done manually. In this module, we
are going to focus on the automated method because, well, AUTOMATION!

Windows
1. Run PowerShell as administrator
> Set-ExecutionPolicy RemoteSigned

> powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((New-Object


System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/oracle/oci-
cli/master/scripts/install/install.ps1’))”

Linux
1. From the terminal prompt, run:
$ bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 10


Configure the CLI

Before using the CLI, you must provide IAM credentials with appropriate access. The
credentials provided will be separated into profiles and stored in ~/.oci/config

Credentials may either be input manually, or by using the setup command:


$ oci setup config

Sample config file

$ cat ~/.oci/config
[DEFAULT]
user=ocid1.user.oc1..aaaaaaaaja3b5st7wd5lkj245jlk235lk23sdf9sdfdhwlndbm6mf7pznq
fingerprint=8b:cc:27:61:dd:92:22:45:c1:24:f1:3d:84:5f:ee:b4
key_file=/home/opc/.oci/oci_api_key.pem
tenancy=ocid1.tenancy.oc1..aaaaaaaaxy6bh46cdnlfpwerljwelrkjwer23cxtfxhhva2hna
region=us-phoenix-1
compartment-id=ocid1.compartment.oc1..aaaaaaaa3xly5up5a3kyqwekhrqwq46krhqwrwzrmysspva

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 11


CLI Profiles

Profiles allow you to specific multiple sets of credentials within your config file. Once
defined, you may reference the appropriate profile at runtime.

$ oci compute image list --profile dev_compartment

[DEFAULT]


[dev_compartment]
user=ocid1.user.oc1..aaaaaaaaja3b5st7wd5lkj245jlk235lk23sdf9sdfdhwlndbm6mf7pznq
fingerprint=8b:cc:27:61:dd:92:22:45:c1:24:f1:3d:84:5f:ee:b4
key_file=/home/opc/.oci/oci_api_key.pem
tenancy=ocid1.tenancy.oc1..aaaaaaaaxy6bh46cdnlfpwerljwelrkjwer23cxtfxhhva2hna
region=us-phoenix-1
compartment-id=ocid1.compartment.oc1..aaaaaaaa8asdf6lkj7wer5lh3aer0asdv9j

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 12


Advanced Features

Working with the CLI can allow for streamlined operations through automation. The
following features can make reduce the effort of command execution and simplify the
resulting command output.

--output [json | table] – alter the format of the command output


--query – allows input of a JMESPath query to refine the command output
--generate-full-command-json-input – Prints out a JSON document containing all
available options for the specified command.
--from-json – will consume the parameters as defined in the file created by --generate-full-
command-json-input.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 13


Using the --query option

$ oci compute image list

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 14


Using the --query option

$ oci compute image list --query "data [*].{ImageName:\"display-name\", OCID:id}" --output table

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 15


Using the --query option with qualifiers

$ oci compute image list --query \


"data [?contains(\"display-name\", 'Oracle-Linux')].{ImageName:\"display-name\", OCID:id}" --output table

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 16


Working with JSON input templates

As we mentioned earlier, the command parameter --generate-full-command-json-input can


be used to create a template shell into which you may configure specific values. This is
great for creating resource templates such as a development compute instance.

$ oci compute instance launch --generate-full-command-json-input > compute_template.json

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 17


Launch a Compute instance with the JSON template

$ oci compute instance launch --from-json file://compute_template.json

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 18


Using a script to orchestrate several tasks

The following is an example of a simple BASH script. In the script we launch a new
instance, wait for it to respond to an SSH request, then test the sample website.

#!/bin/bash
instance_id=$(oci compute instance launch --from-json file://compute_template.json \
--query “data.id” | sed –e ‘s/^”//’ –e s/”$//’
pub_ip=$(oci compute instance list-vnics --instance-id $instance_id --query \
“data [*].\”public-ip\”” | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}’)

# verify SSH connectivity


ssh -qi ~/.ssh/id_rsa opc@$pub_ip
while [ $? -ne 0 ]; do
echo "Checking SSH connectivity“ && sleep 10
ssh -qi ~/.ssh/id_rsa opc@$pub_ip
done
echo "SSH is up - lets move on!“ && sleep 3

#run a simple test


curl http://$pub_ip/testpage.html

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 19


CLI Documentation

• Oracle CLI Documentation


https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/cliconcepts.htm
• JMESpath information
http://jmespath.org/

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 20


Chef on OCI

Chef is one of the industry’s leading configuration management tools. Used for deploying
and managing host and application configuration, it can also be used to provision OCI
resources. Additionally, Chef integrates with Terraform as a provisioner allowing customers
to combine tools to achieve maximum benefit.
We will talk about Terraform provisioners in the next section.

In this section, we will focus on how Chef can be utilized to automate the provisioning or
resources and management of application configuration.

To learn more about getting the most out of Chef, visit their education site:
https://learn.chef.io/

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 21


Basic Chef Concepts

For those already using Chef, these terms should sound familiar. Lets run through a quick
review.

Cookbook A cookbook is the fundamental unit of configuration and policy distribution. It defines a
scenario and contains everything that is required to support that scenario.
Recipe A recipe is akin to a configuration element. It should define everything that is required to
configure a part of the system.
Template A template is used to generate static files. It leverages Embedded Ruby (ERB) to allow
for dynamic content. At runtime, variables may be replaced by values relevant to the
application or the environment.
Attribute An attribute is a specific detail about a node. It might be data retrieved from the
operating system by Ohai*, or a specific value defined by the user.
Data bag A data bag is a global variable stored as JSON and is accessible from the Chef server.
Data bags can be encrypted making them a great choice for the management and
distribution of secrets.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 22


Samples – Recipe / Template / Attribute

Recipe Template
service 'nginx’ do geo $<%= @remote_ip_var %> $authorized_ip {
supports :status => true, :restart => true, :reload => true default no;
End <% @authorized_ips.each do |ip| %>
<%= "#{ip} yes;" %>
template 'authorized_ip’ do <% end %>
path "#{node['nginx']['dir']}/authorized_ip“ }
source 'modules/authorized_ip.erb’
owner 'root’
group 'root’
mode '0755’
variables( Attributes
:remote_ip_var => node['nginx']['remote_ip_var’], node.default['nginx']['remote_ip_var’] = 'remote_addr’
:authorized_ips => node['nginx']['authorized_ips'] ) node.default['nginx']['authorized_ips’] = ['127.0.0.1/32’]
notifies :reload, 'service[nginx]', :immediately node.default['nginx’][‘conf_dir’] = [‘/opt/nginx/conf’]
end

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 23


Chef Infrastructure Concepts

• Chef DK, or Development Kit includes a collection of tools that you use to interact with
the Chef Server. Knife is the command line tool that we will focus on in this course.
• The Chef Server acts as a Hub for your configuration data. It also manages interaction
with the Chef agent that is installed on client servers.
• Clients / Nodes run the chef client and interact with the Chef Server to retrieve
configuration data periodically.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 24


Knife OCI Plugin

Chef can be used to configure and manage resources in your Oracle Cloud Infrastructure,
similar to how you may already be using it on-premesis. However, the knife utility can be
extended by the OCI plugin. This will enable you to interact with the OCI API’s directly from
the knife tool.

Install
$ chef gem install knife-oci or $ gem install knife-oci

Configure
Utilizes ~/.oci/config that is required by the OCI Command Line Interface
Requires additional entries into the knife.rb file
knife[:oci_config_file] = ‘~/.oci/alternate_config_file’ #optional
knife[:oci_profile] = ‘NOT_DEFAULT_PROFILE’ #optional
knife[:compartment_id] = ‘ocid1.compartment.oc1..aaaaaaaaaadfjl6xfziasefl38afel3alwifea’

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 25


Bootstrap an existing compute instance

Leveraging appropriate security credentials, Chef is capable of applying a configuration


profile to a remote instance. This means we have the option to create resources manually,
then bootstrap them into our Chef ecosystem.

Steps
1. Provision a compute resource and assign the appropriate public key
2. Use the knife command to connect remotely and apply the desired configuration
$ knife bootstrap 129.146.22.221 --ssh-user opc --sudo --identity-file ~/.ssh/id_rsa
--node-name chef-client-1 --run-list ‘recipe[learn_chef_httpd]’
3. Wait for the configuration to be applied. This will also install the chef agent on the server
and henceforth it will check in regularly with the Chef server

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 26


Knife OCI – Create a compute resource

knife oci server create


--availability-domain 'kIdk:PHX-AD-1'
--compartment-id 'ocidv1:tenancy:oc1:phx:1460406592660:aaaaaaaab4faofrfkxecohhjuivjq26a13'
--image-id 'ocid1.image.oc1.phx.aaaaaaaaqutj4qjxihpl4mboabsa27mrpusygv6gurp47katabcvljmq3puq'
--shape 'VM.Standard2.1'
--subnet-id 'ocid1.subnet.oc1.phx.aaaaaaaaxlc5cv7ewqr343ms4lvcpxr4lznsf4cbs2565abcm23d3cfebrex'
--ssh-authorized-keys-file ~/.keys/id_rsa.pub
--display-name myinstance
--identity-file ~/.keys/id_rsa
--run-list 'recipe[learn_chef_httpd, fmw-chef-cookbook::service_bus]'
--region us-phoenix-1

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 27


Chef Documentation

• Learn how to get the most out of Chef


https://learn.chef.io
• Chef Knife plugin for OCI
https://github.com/oracle/knife-oci
• Documentation for Chef Knife plugin
https://github.com/oracle/knife-oci/blob/master/README.md
• Sample Oracle cookbooks for Chef
https://github.com/oracle/chef-samples

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 28


Terraform – built by HashiCorp

Provision
• Vagrant: Create and configure portal development environments
• Packer: Create platform-specific machine images from a single source
• Terraform: Create, combine, and manage infrastructure across multiple providers

Secure
• Vault: Centrally store, secure, and control access to distributed secrets.

Run
• Nomad – Cluster manager and scheduler to deploy across any infrastructure
• Consul – Distributed, highly-available tool for service discover, configuration, and
orchestration

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 29


HashiCorp Configuration Language (HCL)

HCL is a simple, flexible language that supports comments, auto-formatting, and is


interoperable with JSON.

HCL can reference creation details of other entities in the template, and can also consume
OS-level environment variables, making it adaptable to your needs.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 30


Basic Terraform File Format (.tf)

Terraform configuration is written into files named .tf files.


It is based on the HashiCorp Configuration Language (HCL) https://github.com/hashicorp/hcl

JSON is supported for code generation purposes. {


"keyword1": [
{
The configuration takes the form: "some_name": [
{
keyword1 "some_name" { "key": "value",
"nested": [
key = "value" {
"key": "value"
nested { }
]
key = "value' }
} ]
}
} ]
}
Compare to JSON

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 31


Getting Started with Terraform – Hello, World!

• Install using apt, yum, choco, brew


• Create a .tf file in a workspace and apply it
demo] $ vi helloworld.tf)
output “myMessage” { value = “Hello, world!” }
demo] $ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed

Outputs:

myMessage = “Hello, world!”

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 32


Terraform Providers

After installing Terraform, you will need to set up the OCI Provider.
Providers abstract the APIs from the given third party in order to create infrastructure.
Example:
provider "oci" {
tenancy_ocid = "${var.tenancy_ocid}"
user_ocid = "${var.user_ocid}"
fingerprint = "${var.fingerprint}"
private_key_path = "${var.private_key_path}"
region = "${var.region}"
}

The OCI provider enables Terraform to create, manage, and destroy resources in your
tenancy.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 33


Terraform Resources

Once a provider is configured, you may begin using that provider’s resources. With the OCI
provider, you may create resources such as compute instances, databases, block and object
storage, and networks.

The following example creates a new compute instance:


resource "oci_core_instance" "TFInstance" {
availability_domain = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[var.AD - 1],"name")}"
compartment_id = "${var.compartment_ocid}"
display_name = "TFInstance"
hostname_label = "instance1"
image = "${lookup(data.oci_core_images.OLImageOCID.images[0], "id")}"
shape = "${var.InstanceShape}" component provider type name
subnet_id = "${var.SubnetOCID}"
metadata {
ssh_authorized_keys = "${var.ssh_public_key}"
user_data = "${base64encode(file(var.BootStrapFile))}"
}
}

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 34


Terraform Planning Phase

Once we have put together a configuration to


try we can dry-run test this with the planning
phase.

"terraform plan" will take the configuration


and give a detailed report on which
resources will be created, deleted or modified
plus identify what dependent resources are
effected by these changes.

terraform plan -out=plan1

Saving the plan is useful to ensure that all


the steps in the plan were actually applied.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 35


Terraform Apply

Once the plan looks good we can go and


apply the configuration.

$ terraform apply

There is also an option to use saved


plans
for an apply operation.

$ terraform apply plan1

Plan and apply can also target particular


resource(s) using the -target flag.

Plans that are too old will be detected,


they are created against a given version
of the terraform.tfstate file.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 36


Terraform Destroy

When infrastructure needs to be retired, destroying it


and all of its dependencies is straightforward with

$ terraform destroy

Terraform destroy will ask for permission, requiring an


explicit "yes" as input. Terraform when destroying an
infrastructure is very thorough.

If a resource is change or removed in the .tf file, the state file


will detect this and change or remove the resource
on the next apply.

Tainting may also be used to force the recreation of a


resource. There are also lifecycle directives available to
protect resources if needed.

$ terraform plan -destroy - Shows what will be


destroyed without actually doing it.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 37


Terraform Variables

In these examples we saw some variables, like compartment_id, image, shape_id. Ideally variables defined
in a "variables.tf" where defaults can be supplied.

Variables can be string, list, boolean and map. Map Variable

String Variables variable "environment" { default = "dev" }


variable "shape" {
type = "map"
# Choose an Availability Domain
default = {
variable "AD" { dev = "VM.Standard1.2"
default = "1" test = "VM.Standard1.4"
} prod = "BM.Standard1.36"
variable "InstanceShape" { }
default = "VM.Standard1.2" }
}
resource "oci_core_instance" "app-server" {
image = "${var.image}"
variable "InstanceImageDisplayName" {
shape = "${lookup(var.instance_type, var.environment)}"
default = "Oracle-Linux-7.4-2017.10.25-0" subnet_id = "${var.subnet_id}"
} }

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 38


Assigning and Overriding Variables

Variables without default values have to have a value assigned.

Variables that have no default value set will cause terraform to prompt for the variable during a plan or apply.

Default variables can be overridden by the environment, command line, tfvars file, or inline.

An example of overriding a variable from the command line is as follows:

$ terraform apply -var 'InstanceShape=VM.Standard1.4'

A .tfvars file can also be used to set variables and their values

instance_type="VM.Standard1.2"

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 39


Terraform Outputs

Terraform can be directed to display the variables that are generated dynamically as pat of the process of
creating the infrastructure.

For example, after a run we might want to see the public ip of the host:
$ cat outputs.tf
output "InstancePrivateIP" { value = ["${data.oci_core_vnic.InstanceVnic.private_ip_address}"]}
output "InstancePublicIP" { value = ["${data.oci_core_vnic.InstanceVnic.public_ip_address}"]}

After a terraform apply:

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.


State path:
Outputs:
InstancePrivateIP = [ 10.0.0.10 ]
InstancePublicIP = [ 129.146.3.173]

Outputs are often used to facilitate interaction with other infrastructure tools. Terraform show (human
readable) and terraform.tfstate file also store these outputs.

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 40


Provisioners

Terraform can also integrate with provisioners like Chef, puppet, Ansible, shells scripts. An example below
is using a provisioner to remote-exec a command to touch a file.

$ cat remote-exec.tf
resource "null_resource" "remote-exec" {
depends_on = ["oci_core_instance.TFInstance"]

provisioner "remote-exec" {
connection {
agent = false
timeout = "10m"
host = "${data.oci_core_vnic.InstanceVnic.public_ip_address}"
user = "opc"
private_key = "${var.ssh_private_key}"
}

inline = [
"touch ~/IMadeAFile.Right.Here",
]
}
}

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 41


Terraform Resource Graph Visualization

Terraform builds dependency graphs for planning state management and more.
$ terraform graph | dot –Tpng > tgraph1.png

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 42


Terraform – Pros and Cons

Pros
• Vault, Consult, Nomad, Packer, Atlas all weave into the Terraform story
• Good for starting simple and evolving to more complex architecture
• Encourages the use of immutable infrastructure.
• Frequent releases, good project vitality, commercial support available
• Tool designed only for provisioning infrastructure - tries to keep clutter out of the concept

Cons
• Importing existing infrastructure challenging
• Configuration and server management tools are still needed. If those tools can serve the
infrastructure provisioning needs, then terraform may be extraneous in some cases.
• Not all application architectures support the concept of immutability

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 43


Compare and contrast: Terraform, CloudFormation, Ansible

Terraform CloudFormation Ansible

Syntax HCL JSON YAML

Manage Existing
Difficult No Yes
Deployments

State Management Yes No Yes

Third Party Providers 68+ No Many++

Infrastructure Immutable Immutable Mutable

Agent/Master No / No No / No No / No

Type Declarative Declarative Procedural

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 44


Terraform Resources

• Getting Started with Terraform - Kirill Shirinkin


978-1-78646-510-8
http://techbus.safaribooksonline.com/book/operating-systems-and-server-
administration/9781786465108

• Terraform: Up and Running - Yevgeniy Brikman


978-1-4919-7708-8
http://techbus.safaribooksonline.com/book/operating-systems-and-server-
administration/virtualization/9781491977071

• The Terraform Book - James Turnbull


978-0-9888202-5-8
https://terraformbook.com/

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 45


Hands-on Labs

Time to get your hands on the tools!

1. Getting started with the OCI Command Line Interface (30 minutes)
2. Getting started with Terraform (60 minutes)

Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 1 - 46

Potrebbero piacerti anche