Azure Container Instance (ACI)

Azure 容器实例(ACI)提供了在 Azure 中运行容器的最简捷方式,它不需要用户配置任何虚拟机或其它高级服务。ACI 适用于快速突发式增长和资源调整的业务,但功能相对比较简单。对于需要完整容器集群编排功能的场景建议使用 ACS 或 AKS。

ACI 的优势包括

  • 不需要用户配置和管理虚拟机就可以提供虚拟机级别的安全隔离
  • 启动快速
  • 支持自定义大小
  • 支持绑定公网IP和持久化存储
  • 支持Linux 和 Windows 容器
  • 支持容器组将多个容器运行在一起(类似于 Kubernetes Pod),它们共享相同的生命周期、网络协议栈、IP地址以及存储
  • 可以通过aci-connector-k8s将 ACI 作为 Kubernetes 集群的一个无限 Node 使用

注意:目前 ACI 仅在 westus、eastus 和 westeurope 等区域开放。

入门示例

# 创建资源组
az group create --name myResourceGroup --location eastus

# 创建容器(对应 docker run)
az container create --name mycontainer --image microsoft/aci-helloworld --resource-group myResourceGroup --ip-address public

# 查询容器(对应 docker ps或 docker inspect)
az container show --name mycontainer --resource-group myResourceGroup [-o table/json]

# 查询容器日志
az container logs --name mycontainer --resource-group myResourceGroup

# 删除容器
az container delete --name mycontainer --resource-group myResourceGroup

容器组

支持容器组将多个容器运行在一起(类似于 Kubernetes Pod),它们共享相同的生命周期、网络协议栈、IP地址以及持久化存储。容器组常以 sidecar 模式运行一组功能管理的容器,如应用程序和监控容器、应用程序和日志容器等。

目前,容器组仅支持以模板的方式来运行。模板格式为

{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
"container1name": "aci-tutorial-app",
"container1image": "microsoft/aci-helloworld:latest",
"container2name": "aci-tutorial-sidecar",
"container2image": "microsoft/aci-tutorial-sidecar"
},
"resources": [
{
"name": "myContainerGroup",
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2017-08-01-preview",
"location": "[resourceGroup().location]",
"properties": {
"containers": [
{
"name": "[variables('container1name')]",
"properties": {
"image": "[variables('container1image')]",
"resources": {
"requests": {
"cpu": 1,
"memoryInGb": 1.5
}
},
"ports": [
{
"port": 80
}
]
}
},
{
"name": "[variables('container2name')]",
"properties": {
"image": "[variables('container2image')]",
"resources": {
"requests": {
"cpu": 1,
"memoryInGb": 1.5
}
}
}
}
],
"osType": "Linux",
"ipAddress": {
"type": "Public",
"ports": [
{
"protocol": "tcp",
"port": "80"
}
]
}
}
}
],
"outputs": {
"containerIPv4Address": {
"type": "string",
"value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups/', 'myContainerGroup')).ipAddress.ip]"
}
}
}

而部署容器组也需要使用 az group deployment 命令

az group deployment create --name myContainerGroup --resource-group myResourceGroup --template-file azuredeploy.json

部署成功后就可以通过 az container 命令来查看或操作容器了(使用 --container-name 指定操作的是哪个容器)。

私有镜像

私有镜像可以存储在 Azure 容器注册表(ACR)中。

# Create ACR
az acr create --resource-group myResourceGroup --name <acrName> --sku Basic --admin-enabled true

# Login
az acr login --name <acrName>

# Tag the image.
az acr list --resource-group myResourceGroup --query "[].{acrLoginServer:loginServer}" --output table
docker tag azure-vote-front <acrLoginServer>/azure-vote-front:redis-v1

# push image
docker push <acrLoginServer>/azure-vote-front:redis-v1

# List images.
az acr repository list --name <acrName> --output table

使用私有镜像创建容器时,需要通过 --registry-password 选项给每个容器设置密码(比 docker login 麻烦一些):

# Query password.
az acr credential show --name <acrName> --query "passwords[0].value"
# Create container.
az container create --name aci-tutorial-app --image <acrLoginServer>/aci-tutorial-app:v1 --cpu 1 --memory 1 --registry-password <acrPassword> --ip-address public --ports 80 -g myResourceGroup

或者在部署模板(比如上述容器组示例)中设置

"imageRegistryCredentials": [
{
"server": "[parameters('imageRegistryLoginServer')]",
"username": "[parameters('imageRegistryUsername')]",
"password": "[parameters('imageRegistryPassword')]"
}
]

持久化存储

必须先创建 Azure 文件共享,才能将其用于 Azure 容器实例。

# Create the storage account
az storage account create -n mycontainerstorage -g myResourceGroup --sku Standard_LRS

# Export the connection string as an environment variable, this is used when creating the Azure file share
AZURE_STORAGE_CONNECTION_STRING=$(az storage account show-connection-string -n mycontainerstorage -g myResourceGroup -o tsv)

# Create the share
az storage share create -n myacishare

# Get storage account key.
STORAGE_ACCOUNT="mycontainerstorage"
STORAGE_KEY=$(az storage account keys list --resource-group myResourceGroup --account-name mycontainerstorage --query "[0].value" -o tsv)

持久化存储也是需要通过模板来引用,创建下面的模板文件

{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageaccountname": {
"type": "string"
},
"storageaccountkey": {
"type": "securestring"
}
},
"resources":[{
"name": "hellofiles",
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2017-08-01-preview",
"location": "[resourceGroup().location]",
"properties": {
"containers": [{
"name": "hellofiles",
"properties": {
"image": "seanmckenna/aci-hellofiles",
"resources": {
"requests": {
"cpu": 1,
"memoryInGb": 1.5
}
},
"ports": [{
"port": 80
}],
"volumeMounts": [{
"name": "myvolume",
"mountPath": "/aci/logs/"
}]
}
}],
"osType": "Linux",
"ipAddress": {
"type": "Public",
"ports": [{
"protocol": "tcp",
"port": "80"
}]
},
"volumes": [{
"name": "myvolume",
"azureFile": {
"shareName": "myacishare",
"storageAccountName": "[parameters('storageaccountname')]",
"storageAccountKey": "[parameters('storageaccountkey')]"
}
}]
}
}]
}

最后部署容器

# deploy container group
az group deployment create --name hellofilesdeployment --template-file hellofiles.json --resource-group myResourceGroup --parameters storageaccountname=$STORAGE_ACCOUN storageaccountkey=$STORAGE_KEY

# list container
az container list -g myResourceGroup -o table

Kubernetes集成

aci-connector-k8s 可以将 ACI 作为 Kubernetes 集群的一个无限 Node 使用。

下载 aci-connector-k8s 源码后,可以运行 examples/generateManifest.py 命令自动生成一个部署 aci-connector 的配置(不包含RBAC配置)。

python3 generateManifest.py -g myResourceGroup -s <my-subscription-id> -l westus

而在开启RBAC的系统中,需要配置相应的权限,比如使用下面的部署文件

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: aci-connector
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: aci-connector
spec:
serviceAccount: aci-connector
containers:
- name: aci-connector
image: microsoft/aci-connector-k8s:latest
imagePullPolicy: Always
env:
- name: AZURE_CLIENT_ID
value: <your-client-id>
- name: AZURE_CLIENT_KEY
value: <your-client-key>
- name: AZURE_TENANT_ID
value: <your-tenant-id>
- name: AZURE_SUBSCRIPTION_ID
value: <your-subsription-id>
- name: ACI_RESOURCE_GROUP
value: <your-resource-group>
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: aci-connector
---
apiVersion: v1
kind: List
items:
- apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: "aci-connector"
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods", "pods/status"]
verbs: ["get","list","watch","create","patch","update","delete"]
- apiGroups: [""]
resources: ["nodes", "nodes/status"]
verbs: ["get","list","watch","create","patch","update","delete"]
- apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: "aci-connector"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: "aci-connector"
subjects:
- apiGroup: ""
kind: ServiceAccount
name: "aci-connector"
namespace: "default"

这样,Deployment部署后,很快就可以发现它自动创建了一个 aci-connector 的 Node

# kubectl get node aci-connector
NAME STATUS ROLES AGE VERSION
aci-connector Ready <none> 1m v1.6.6

这样,Pod可以通过指定 nodeName 或者容忍 taint azure.com/aci=NoSchedule 调度到ACI上面:

apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
run: nginx
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
dnsPolicy: ClusterFirst
nodeName: aci-connector
# kubectl get pods -l run=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 28s x.x.x.x aci-connector

# az container list -g myResourceGroup -o table
Name ResourceGroup ProvisioningState Image IP:ports CPU/Memory OsType Location
------ --------------- ------------------- ------- ---------------- --------------- -------- ----------
nginx myResourceGroup Succeeded nginx x.x.x.x:80 1.0 core/1.5 gb Linux westus

参考文档

Feisky wechat
微信公众号订阅