Terraform 是一个 IT 基础架构自动化编排工具,它的口号是 "Write, Plan, and create Infrastructure as Code", 基础架构即代码。Terraform 几乎可以支持所有市面上能见到的云服务。

Terraform 要解决的就是在云上那些硬件资源分配管理的问题。相比较 Chef, Puppet, Ansible 这些软件配置工具,Terraform 提供的是软件配置之前,软硬件(基础)资源构建的问题。

当我们创建资源时,使用 terraform 比 ansible 好在哪里?

  • 并发创建,速度快
  • 扩容/缩容 很方便,改一个数字就行
  • state 文件记录资源状态

就创建资源这个角度来说,terraform 和 ansible 都能完成,terraform能够并发,效率高很多,另外它在资源生产成功之后会在本地以一个state文件的形式记录整个资源的详细信息,而这些信息的记录使得整个模板所定义的资源可以保证前后端的高度一致性,可以有利于后续对于整个一套资源的有效的版本控制。同时Terraform拥有一个Data Source功能,利用这个功能可以实现对于已有资源的获取,比如在生产资源之前想要查看当前有哪些可用区,有哪些可用镜像等,所有的这些都可以通过DataSource实现。

Terraform 和 Ansible 的结合

  • terraform 调用 ansible

    • Provisioner(local-exec, remote-exec) (官方推荐)
  • ansible 调用 terraform
    • Ansible module for terraform(官方推荐)
  • 其它方式
    • terraform output 生成 inventory 给 ansible 使用(手工)
    • Terraform template 渲染后,生成 inventory 给 ansible 使用(自动)
    • Terraform创建的时候使用tag,ansible直接对tag 操作(完全解耦,云平台,动态主机列表)
    • 第三方工具解析state文件给ansible使用。 比如 Terraform - Inventory 这个第三方工具能够将Terraform生产出的资源转化为Ansible想要的Inventory文件

安装软件

  1. 下载zip 文件 https://www.terraform.io/downloads.html
  2. 解压后直接就能用。把文件放到合适的路径,比如 /usr/local/bin

生成配置文件

  1. 新建目录,并生成配置文件,比如 azure.tf

    # Configure the provider
    provider "azurerm" {version = "=1.20.0"
    }# Create a new resource group
    resource "azurerm_resource_group" "rg" {name     = "royTR"location = "eastasia"
    }
    

    配置有两部分:provider 和 resource。provider 告知与哪一个云平台打交道,这里是Azure;如果使用AWS,这里就写成 provider "aws"。第二部分是资源,说明要生成哪些资源,例子中是resource group,还可以继续往下写,比如网卡,存储,虚拟机等。

格式:resource resource_type resource_name { }

A resource block has two string parameters before opening the block: the resource type (first parameter) and the resource name (second parameter). The combination of the type and name must be unique in the configuration.

我已经通过Azure CLI 登陆过,所以上面provider 部分没有提供用户验证信息,如果单独配置,使用如下形式:

# Configure the Microsoft Azure Provider
provider "azurerm" {# More information on the authentication methods supported by# the AzureRM Provider can be found here:# http://terraform.io/docs/providers/azurerm/index.htmlsubscription_id = "..."client_id       = "..."client_secret   = "..."tenant_id       = "..."
}

这些信息怎么获取? 可以用Azure CLI 的命令生成:

az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/${SUBSCRIPTION_ID}"

详细信息参考微软文档

创建资源

  1. 初始化

    在初始化项目的时候,Terraform 会解析目录下的*.tf文件并加载相关的 provider插件。

$ terraform initInitializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "azurerm" (1.20.0)...Terraform has been successfully initialized!You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
  1. apply changes

    This output shows the execution plan, describing which actions Terraform will take in order to change real infrastructure to match the configuration.

    $ terraform apply .An execution plan has been generated and is shown below.
    Resource actions are indicated with the following symbols:+ createTerraform will perform the following actions:+ azurerm_resource_group.rgid:       <computed>location: "eastasia"name:     "royTR"tags.%:   <computed>Plan: 1 to add, 0 to change, 0 to destroy.Do you want to perform these actions?Terraform will perform the actions described above.Only 'yes' will be accepted to approve.Enter a value: yes  # 查看 execution plan 符合期望,输入 yes 确认,之后真正执行。azurerm_resource_group.rg: Creating...location: "" => "eastasia"name:     "" => "royTR"tags.%:   "" => "<computed>"
    azurerm_resource_group.rg: Creation complete after 1s (ID: /subscriptions/7c91db0e-eb7f-491b-997f-32cf55b85dea/resourceGroups/royTR)Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
    
  1. 查看状态
$ terraform state show
id       = /subscriptions/7c91db0e-eb7f-491b-997f-32cf55b85dea/resourceGroups/royTR
location = eastasia
name     = royTR
tags.%   = 0

更多

$ terraform state list
module.roy-azure.azurerm_availability_set.hdp-avset
module.roy-azure.azurerm_network_interface.bastion-nic
...
$ terraform state show module.roy-azure.azurerm_virtual_machine.hdp-slave[1]
...
location                                                         = japaneast
name                                                             = roy-tf0-hdp-slave-02
...
$ terraform state show module.roy-azure.azurerm_network_interface.hdp[0]
...
ip_configuration.0.load_balancer_backend_address_pools_ids.#       = 0
ip_configuration.0.load_balancer_inbound_nat_rules_ids.#           = 0
ip_configuration.0.name                                            = hdp-01-ip-conf
....
private_ip_address                                                 = 10.0.10.8
...

更改资源

  1. 改配置

    修改刚才的文件,添加tag部分。

   # Configure the providerprovider "azurerm" {version = "=1.20.0"}# Create a new resource groupresource "azurerm_resource_group" "rg" {name     = "royTR"location = "eastasia"tags {environment = "TF sandbox"}}
  1. apply changes

    An execution plan has been generated and is shown below.
    Resource actions are indicated with the following symbols:~ update in-placeTerraform will perform the following actions:~ azurerm_resource_group.rgtags.%:           "0" => "1"tags.environment: "" => "TF sandbox"Plan: 0 to add, 1 to change, 0 to destroy.
    

销毁基础设施

terraform destroy

$ terraform destroy
azurerm_resource_group.rg: Refreshing state... (ID: /subscriptions/xxxx/resourceGroups/royTR-rg)An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:- destroyTerraform will perform the following actions:- azurerm_resource_group.rgPlan: 0 to add, 0 to change, 1 to destroy.Do you really want to destroy all resources?Terraform will destroy all your managed infrastructure, as shown above.There is no undo. Only 'yes' will be accepted to confirm.Enter a value: yesazurerm_resource_group.rg: Destroying... (ID: /subscriptions/xxxxx/resourceGroups/royTR-rg)
azurerm_resource_group.rg: Still destroying... (ID: /subscriptions/xxxx/resourceGroups/royTR-rg, 10s elapsed)
azurerm_resource_group.rg: Still destroying... (ID: /subscriptions/xxxxx/resourceGroups/royTR-rg, 20s elapsed)
azurerm_resource_group.rg: Still destroying... (ID: /subscriptions/xxxxx/resourceGroups/royTR-rg, 30s elapsed)
azurerm_resource_group.rg: Still destroying... (ID: /subscriptions/xxxxx/resourceGroups/royTR-rg, 40s elapsed)
azurerm_resource_group.rg: Destruction complete after 48sDestroy complete! Resources: 1 destroyed.

单独删除一个资源:

$ terraform destroy -target=module.roy-azure.azurerm_virtual_machine.hdp[2]
...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:- destroyTerraform will perform the following actions:- module.roy-azure.azurerm_virtual_machine.hdp[2]Plan: 0 to add, 0 to change, 1 to destroy.Do you really want to destroy all resources?
....
Destroy complete! Resources: 1 destroyed.

资源的依赖关系

要创建一个VM,需要一些资源已经具备,这些资源可能包括:

  • Resource group
  • Virtual network and subnet
  • Public IP
  • Network security group
  • Network interface

先来一个简单的例子,创建网络:

# Create virtual network
resource "azurerm_virtual_network" "vnet" {name                = "royTFVnet"address_space       = ["10.0.0.0/16"]location            = "${azurerm_resource_group.rg.location}"resource_group_name = "${azurerm_resource_group.rg.name}"
}

location等部分引入了插值(interpolation),它已经在前面的资源定义,之后直接调用,格式是 TYPE.NAME.ATTRIBUTE.
Azure 网络和虚拟机的基础架构如下图所示:

azure_vm_structure.png

把上面的图,变成代码,创建VM需要的整个文件:

# Configure the provider
provider "azurerm" {version = "=1.20.0"
}# Create a new resource group
resource "azurerm_resource_group" "rg" {name     = "royTR"location = "eastasia"tags {environment = "TF sandbox"}
}# Create virtual network
resource "azurerm_virtual_network" "vnet" {name                = "royTFVnet"address_space       = ["10.0.0.0/16"]location            = "${azurerm_resource_group.rg.location}"resource_group_name = "${azurerm_resource_group.rg.name}"
}# Create subnet
resource "azurerm_subnet" "subnet" {name                 = "royTFSubnet"resource_group_name  = "${azurerm_resource_group.rg.name}"virtual_network_name = "${azurerm_virtual_network.vnet.name}"address_prefix       = "10.0.1.0/24"#address_prefix       = "${cidrsubnet(var.cluster_cidr, 8, 10)}"
}# Create public IP
resource "azurerm_public_ip" "publicip" {name                         = "myTFPublicIP"location                     = "${azurerm_resource_group.rg.location}"resource_group_name          = "${azurerm_resource_group.rg.name}"public_ip_address_allocation = "dynamic"}# Create Network Security Group and rule
resource "azurerm_network_security_group" "nsg" {name                = "myTFNSG"location            = "${azurerm_resource_group.rg.location}"resource_group_name = "${azurerm_resource_group.rg.name}"security_rule {name                       = "SSH"priority                   = 1001direction                  = "Inbound"access                     = "Allow"protocol                   = "Tcp"source_port_range          = "*"destination_port_range     = "22"source_address_prefix      = "*"destination_address_prefix = "*"}
}# Create network interface
resource "azurerm_network_interface" "nic" {name                      = "myNIC"location                  = "${azurerm_resource_group.rg.location}"resource_group_name       = "${azurerm_resource_group.rg.name}"network_security_group_id = "${azurerm_network_security_group.nsg.id}"ip_configuration {name                          = "myNICConfg"subnet_id                     = "${azurerm_subnet.subnet.id}"private_ip_address_allocation = "dynamic"public_ip_address_id          = "${azurerm_public_ip.publicip.id}"}
}# Create a Linux virtual machine
resource "azurerm_virtual_machine" "vm" {name                  = "royTFVM"location              = "${azurerm_resource_group.rg.location}"resource_group_name   = "${azurerm_resource_group.rg.name}"network_interface_ids = ["${azurerm_network_interface.nic.id}"]vm_size               = "Standard_DS1_v2"storage_os_disk {name              = "myOsDisk"caching           = "ReadWrite"create_option     = "FromImage"managed_disk_type = "Premium_LRS"}storage_image_reference {publisher = "Canonical"offer     = "UbuntuServer"sku       = "16.04.0-LTS"version   = "latest"}os_profile {computer_name  = "royvm"admin_username = "royzeng"}os_profile_linux_config {disable_password_authentication = truessh_keys {path     = "/home/royzeng/.ssh/authorized_keys"key_data = "ssh-rsa AAAAB3Nz{snip}hwhqT9h"}}}

使用 Provisioners 进行环境配置

Provisioners 可以在资源创建/销毁时在本地/远程执行脚本。

Provisioners 通常用来引导一个资源,在销毁资源前完成清理工作,进行配置管理等。

Provisioners拥有多种类型可以满足多种需求,如:文件传输(file),本地执行(local-exec),远程执行(remote-exec)等 Provisioners可以添加在任何的resource当中:

# Create a Linux virtual machine
resource "azurerm_virtual_machine" "vm" {<...snip...>provisioner "file" {connection {type        = "ssh"user        = "royzeng"private_key = "${file("~/.ssh/id_rsa")}"}source      = "newfile.txt"destination = "newfile.txt"}provisioner "remote-exec" {connection {type        = "ssh"user        = "royzeng"private_key = "${file("~/.ssh/id_rsa")}"}inline = ["ls -a","cat newfile.txt"]}}

上面的方式适合有public ip,能够直接连接的机器,对于不能直接连接的vm,通过跳板来实现。

官方的方法,定义 bastion_host

resource "null_resource" "connect_private" {connection {bastion_host = "${aws_instance.bastion.public_ip}"host         = "${aws_instance.private.private_ip}"user         = "ubuntu"private_key  = "${file("~/.ssh/id_rsa")}"}provisioner "remote-exec" {inline = ["echo 'CONNECTED to PRIVATE!'"]}
}

或者

resource "azurerm_virtual_machine" "vm" {<...snip...>provisioner "remote-exec" {connection {bastion_host= "${azurerm_public_ip.bastion.ip_address}"type        = "ssh"user        = "${var.admin-username}"private_key = "${file("~/.ssh/id_rsa")}"}inline = ["sudo parted /dev/disk/azure/scsi1/lun0 mklabel msdos","sudo parted /dev/disk/azure/scsi1/lun0 mkpart primary 1 100%","sudo partprobe","sleep 5; sudo mkfs.xfs /dev/disk/azure/scsi1/lun0-part1","sudo mkdir /roytest","sudo mount /dev/disk/azure/scsi1/lun0-part1 ${var.mount_path[0]}","echo 'UUID='`sudo blkid -s UUID -o value $(readlink -f /dev/disk/azure/scsi1/lun0-part1)`  ${var.mount_path[0]} 'xfs defaults  0 0' | sudo tee -a /etc/fstab","df -hl | grep /dev/sd"]}
}

另一种方法,用local-exec 来跳转

  provisioner "local-exec" {## 简化方式command = "ssh -o "ProxyCommand ssh -q -W %h:%p -i mykey jump_server” -C 'echo hello'"## 真实环境用的方式command = <<EOFsleep 30; ansible-playbook -i '${element(azurerm_network_interface.master_bind.*.private_ip_address, count.index)},' ${local.ansible_ssh_args} ${var.ansible_path}/mount_disk.yml --extra-vars '{"root_user": "centos","deviceName": "/dev/disk/azure/scsi1/lun0","mountPath": "${var.mount_path}","bind_zone_name": "${var.bind_zone_name}"}'EOF}

使用 null resource 和 trigger 来解耦

为了让ansible 脚本单独运行,而不需要创建或销毁资源,可以用 null_resource 调用 provisioner 来实现。

resource "null_resource" "datanode" {count = "${var.count.datanode}"triggers {instance_ids = "${element(aws_instance.datanode.*.id, count.index)}"}provisioner "remote-exec" {inline = [...]connection {type = "ssh"user = "centos"host = "${element(aws_instance.datanode.*.private_ip, count.index)}"}}
}

输入变量

新建一个文件定义变量

# file variables.tf
---
variable "prefix" {default = "royTF"
}variable "location" { }variable "tags" {type    = "map"default = {Environment = "royDemo"Dept = "Engineering"}
}

文件中 location 部分没有定义,运行terraform的时候,会提示输入:

$ terraform plan -out royplan
var.locationEnter a value: eastasia<...snip...>This plan was saved to: royplanTo perform exactly these actions, run the following command to apply:terraform apply "royplan"

其它输入变量的方式

命令行输入

$ terraform apply \
>> -var 'prefix=tf' \
>> -var 'location=eastasia'

文件输入

$ terraform apply \-var-file='secret.tfvars'

默认读取文件 terraform.tfvars,这个文件不需要单独指定。

环境变量输入

TF_VAR_name ,比如 TF_VAR_location

变量类型

  • list
  • map

对于 list 变量

# 定义 list 变量
variable "image-RHEL" {type = "list"default = ["RedHat", "RHEL", "7.5", "latest"]
}# 调用 list 变量storage_image_reference {publisher = "${var.image-RHEL[0]}"offer     = "${var.image-RHEL[1]}"sku       = "${var.image-RHEL[2]}"version   = "${var.image-RHEL[3]}"}

map 是一个可以被查询的表。

variable "sku" {type = "map"default = {westus = "16.04-LTS"eastus = "18.04-LTS"}
}

查询方式(使用 lookup)

storage_image_reference {publisher = "Canonical"offer     = "UbuntuServer"sku       = "${lookup(var.sku, var.location)}"version   = "latest"
}

输出变量

定义输出

output "ip" {value = "${azurerm_public_ip.publicip.ip_address}"
}

测试

$ terraform apply
...Apply complete! Resources: 0 added, 0 changed, 0 destroyed.Outputs:ip = 52.184.97.1
$ terraform output ip
52.184.97.1

Bug? 第一次运行,ip 输出是空的,terraform output ip 命令的结果也是空的,过一段时间才能看到结果。

$ terraform output -module=roy-azure
bastion-private-ip = 10.0.1.4
bastion-public-ip = 40.115.243.72
cluster_cidr = 10.0.0.0/16
cluster_location = japaneast
cluster_prefix = roy-tf0
cluster_resource_group = roy-tf0-rg
hdp-master-ip = 10.0.10.4,10.0.10.6,10.0.10.7
hdp-master-name = roy-tf0-hdp-master-01,roy-tf0-hdp-master-02,roy-tf0-hdp-master-03
hdp-slave-ip = 10.0.10.5,10.0.10.9,10.0.10.8
hdp-slave-name = roy-tf0-hdp-slave-01,roy-tf0-hdp-slave-02,roy-tf0-hdp-slave-03
k8s-master-ip = 10.0.20.8,10.0.20.5
k8s-master-name = roy-tf0-k8s-master-01,roy-tf0-k8s-master-02
k8s-slave-ip = 10.0.20.6,10.0.20.7,10.0.20.4
k8s-slave-name = roy-tf0-k8s-slave-01,roy-tf0-k8s-slave-02,roy-tf0-k8s-slave-03
virtual_network = roy-tf0-vnet

Data Source

DataSource 的作用可以通过输入一个资源的变量名,然后获得这个变量的其他属性字段。

用 Azure网络 来举例,提供一些信息,查询其它的属性。具体必须提供什么,能查到什么,参考这个链接。

data "azurerm_virtual_network" "test" {name                = "production"resource_group_name = "networking"
}output "virtual_network_id" {value = "${data.azurerm_virtual_network.test.id}"
}output "virtual_network_subnet" {value = "${data.azurerm_virtual_network.test.subnets[0]}"
}

生成主机列表

ansible通过主机列表来连接目标主机,我们就要想办法让terraform来生成。(local-exec 也是一种方式,这是另一种思路:用terraform 调用ansible)

terraform 生成inventory的思路是:从模板到文件,需要先用template_file 渲染成一个字符串,然后用local_file把这个字符串输出到一个文件。

模版文件

## file inventory.tpl[backend]
${bastion_private_ip}[frontend]
${bastion_pub_ip}[all:vars]
ansible_ssh_private_key_file = ${key_path}
ansible_ssh_user = dcpuser

渲染和输出

## file inventory.tfdata "template_file" "inventory" {template = "${file("./test/inventory.tpl")}"vars {bastion_private_ip      = "${element(azurerm_network_interface.bastion-nic.*.private_ip_address, count.index)}"bastion_pub_ip          = "${element(azurerm_public_ip.bastion.*.ip_address, count.index)}"key_path = "~/.ssh/id_rsa"}
}resource "local_file" "save_inventory" {content  = "${data.template_file.inventory.rendered}"filename = "./myhost"
}

运行后,当前目录生成文件myhost

[backend]
13.78.94.242[frontend]
10.0.1.4[all:vars]
ansible_ssh_private_key_file = ~/.ssh/id_rsa
ansible_ssh_user = dcpuser

对于多个主机,使用 join 来把它们合在一起。

File inventory.tf

data  "template_file" "k8s" {template = "${file("./templates/k8s.tpl")}"vars {k8s_master_name = "${join("\n", azurerm_virtual_machine.k8s-master.*.name)}"}
}resource "local_file" "k8s_file" {content  = "${data.template_file.k8s.rendered}"filename = "./inventory/k8s-host"
}

File k8s.tpl

[kube-master]
${k8s_master_name}

Final result

[kube-master]
k8s-master-01
k8s-master-02
k8s-master-03

使用module进行代码的组织管理

Module 是 Terraform 为了管理单元化资源而设计的,是子节点,子资源,子架构模板的整合和抽象。将多种可以复用的资源定义为一个module,通过对 module 的管理简化模板的架构,降低模板管理的复杂度,这就是module的作用。

Terraform中的模块是以组的形式管理不同的Terraform配置。模块用于在Terraform中创建可重用组件,以及用于基本代码组织。每一个module都可以定义自己的input与output,方便代码进行模块化组织。

用模块,可以写更少的代码。比如用下面的代码,调用已有的module 创建vm。

调用官方module

# declare variables and defaults
variable "location" {}
variable "environment" {default = "dev"
}
variable "vm_size" {default = {"dev"   = "Standard_B2s""prod"  = "Standard_D2s_v3"}
}# Use the network module to create a resource group, vnet and subnet
module "network" {source              = "Azure/network/azurerm"version             = "2.0.0"location            = "${var.location}"resource_group_name = "roytest-rg"address_space       = "10.0.0.0/16"subnet_names        = ["mySubnet"]subnet_prefixes     = ["10.0.1.0/24"]
}# Use the compute module to create the VM
module "compute" {source            = "Azure/compute/azurerm"version           = "1.2.0"location          = "${var.location}"resource_group_name = "roytest-rg"vnet_subnet_id    = "${element(module.network.vnet_subnets, 0)}"admin_username    = "royzeng"admin_password    = "Password1234!"remote_port       = "22"vm_os_simple      = "UbuntuServer"vm_size           = "${lookup(var.vm_size, var.environment)}"public_ip_dns     = ["roydns"]
}

调用自己写的module

## file main.cfmodule "roy-azure" {source = "./test"
}## file test/resource.tfvariable "cluster_prefix" {type        = "string"
}
variable "cluster_location" {type        = "string"
}resource "azurerm_resource_group" "core" {name     = "${var.cluster_prefix}-rg"location = "${var.cluster_location}"
}

参考文档

https://docs.microsoft.com/en-us/azure/virtual-machines/linux/terraform-install-configure

https://learn.hashicorp.com/terraform/azure/install_az

Provisioner connections

Terraform example

https://www.terraform.io/docs/providers/azurerm/r/virtual_machine.html

Create a VM cluster with Terraform https://docs.microsoft.com/en-us/azure/terraform/terraform-create-vm-cluster-with-infrastructure

http://aukjan.vanbelkum.nl/2016/02/23/Ansible-inventory-from-Terraform/

Terraform Azure modules https://registry.terraform.io/browse?offset=9&provider=azurerm

How to use Ansible with Terraform https://alex.dzyoba.com/blog/terraform-ansible/

Terraform 学习笔记相关推荐

  1. Reliable Cloud Infrastructure: Design and Process学习笔记

    最后更新2022/03/16 忘记更新对应的学习笔记,补上.这一科有9节,加上0章简介 简介 google cloud的好多功能有点相似,这科内容是介绍应该选什么产品,怎么选择,怎么规划,怎么设计等等 ...

  2. PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call

    您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...

  3. 容器云原生DevOps学习笔记——第三期:从零搭建CI/CD系统标准化交付流程

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  4. 容器云原生DevOps学习笔记——第二期:如何快速高质量的应用容器化迁移

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  5. 2020年Yann Lecun深度学习笔记(下)

    2020年Yann Lecun深度学习笔记(下)

  6. 2020年Yann Lecun深度学习笔记(上)

    2020年Yann Lecun深度学习笔记(上)

  7. 知识图谱学习笔记(1)

    知识图谱学习笔记第一部分,包含RDF介绍,以及Jena RDF API使用 知识图谱的基石:RDF RDF(Resource Description Framework),即资源描述框架,其本质是一个 ...

  8. 计算机基础知识第十讲,计算机文化基础(第十讲)学习笔记

    计算机文化基础(第十讲)学习笔记 采样和量化PictureElement Pixel(像素)(链接: 采样的实质就是要用多少点(这个点我们叫像素)来描述一张图像,比如,一幅420x570的图像,就表示 ...

  9. Go 学习推荐 —(Go by example 中文版、Go 构建 Web 应用、Go 学习笔记、Golang常见错误、Go 语言四十二章经、Go 语言高级编程)

    Go by example 中文版 Go 构建 Web 应用 Go 学习笔记:无痕 Go 标准库中文文档 Golang开发新手常犯的50个错误 50 Shades of Go: Traps, Gotc ...

最新文章

  1. 脚本SFTP定时取Linux服务器文件
  2. 06 Java程序员面试宝典视频课程之Javascript
  3. 谈C/C++指针精髓
  4. ipython安装教程-ipython notebook教程
  5. 什么代码才是线程安全的
  6. jquery --- 监听input框失效
  7. asp.net程序的问题原来是IE造成的,改用firefox就没问题了!
  8. eosio.msig合约源码分析
  9. matlab虚拟现实之V-Realm Builder2建模第二部分
  10. php 创建 cookie文件,php创建、获取cookie及基础要点分析
  11. 纪念贴:历史会证明今天是不是开创新历史的一天
  12. 前言:设计模式六大原则
  13. Qt组态软件设计文章导航
  14. 【源码】日历转换器:格里高利历、波斯历和伊斯兰历法
  15. 菜鸡哈屠教你合并果子
  16. html5相册制作成视频,怎么把照片制作成视频,视频相册制作免费软件|特效多多...
  17. 三菱PlC计数器与定时的使用
  18. 用批处理文件实现同步到个人时间服务器,局域网内时间同步net time的使用
  19. SQL Server 2005数据库教程
  20. python中led是什么意思_用于检测LED闪光灯的Python库

热门文章

  1. Android之简单改变按钮颜色方案
  2. 软件测试基本流程及规范
  3. 2012网络流行语 - 收集
  4. android百度上弄一个蓝圈,iOS 百度地图 定位后蓝色圆圈(精度圈)去除
  5. Python数据库安装
  6. 对比vscode和idea开发前端的优劣
  7. 华为mate40和p40哪个好有什么区别 华为mate40和p40参数对比
  8. 用python画写轮眼_Python爬虫入门-图片下载(写轮眼--Lyon)
  9. Java内存溢出问题排查分析
  10. 对于苹果股票,投资者无需恐慌,像巴菲特一样坚持下去就行