")$
25 | create_resource_group("myresgroup", location="australiaeast")
26 |
27 | # create container registry
28 | acr <- resgroup$create_acr("myacr", location="australiaeast")
29 |
30 | # create Docker image from a predefined Dockerfile
31 | call_docker("build -t newcontainer .")
32 |
33 | # get registry endpoint, upload image
34 | reg <- acr$get_docker_registry()
35 | reg$push("newcontainer")
36 |
37 |
38 | # create Kubernetes cluster with 2 nodes
39 | aks <- resgroup$create_aks("myakscluster",
40 | location="australiaeast",
41 | agent_pools=agent_pool("pool1", 2))
42 |
43 | # give the cluster pull access to the registry
44 | acr$add_role_assignment(aks, "Acrpull")
45 |
46 | # get cluster endpoint, deploy from ACR to AKS with predefined yaml definition file
47 | clus <- aks$get_cluster()
48 | clus$create("model1.yaml")
49 | clus$get("service")
50 | ```
51 |
52 | ---
53 | 
54 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/man/DockerRegistry.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/docker_registry.R
3 | \docType{class}
4 | \name{DockerRegistry}
5 | \alias{DockerRegistry}
6 | \title{Docker registry class}
7 | \description{
8 | Class representing a \href{https://docs.docker.com/registry/}{Docker registry}. Note that this class can be used to interface with any Docker registry that supports the HTTP V2 API, not just those created via the Azure Container Registry service. Use the \link{docker_registry} function to instantiate new objects of this class.
9 | }
10 | \section{Methods}{
11 |
12 | The following methods are available, in addition to those provided by the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class:
13 | \itemize{
14 | \item \code{login(...)}: Do a local login to the registry via \verb{docker login}; necessary if you want to push and pull images. By default, instantiating a new object of this class will also log you in. See 'Details' below.
15 | \item \code{push(src_image, dest_image, ...)}: Push an image to the registry, using \verb{docker tag} and \verb{docker push}.
16 | \item \code{pull(image, ...)}: Pull an image from the registry, using \verb{docker pull}.
17 | \item \code{get_image_manifest(image, tag="latest")}: Gets the manifest for an image.
18 | \item \code{get_image_digest(image, tag="latest")}: Gets the digest (SHA hash) for an image.
19 | \item \code{delete_image(image, digest, confirm=TRUE)}: Deletes an image from the registry.
20 | \item \code{list_repositories()}: Lists the repositories (images) in the registry.
21 | }
22 | }
23 |
24 | \section{Details}{
25 |
26 | The arguments to the \code{login()} method are:
27 | \itemize{
28 | \item \code{tenant}: The Azure Active Directory (AAD) tenant for the registry.
29 | \item \code{username}: The username that Docker will use to authenticate with the registry. This can be either the admin username, if the registry was created with an admin account, or the ID of a registered app that has access to the registry.
30 | \item \code{password}: The password that Docker will use to authenticate with the registry.
31 | \item \code{app}: The app ID to use to authenticate with the registry. Set this to NULL to authenticate with a username and password, rather than via AAD.
32 | \item \code{...}: Further arguments passed to \link[AzureAuth:get_azure_token]{AzureAuth::get_azure_token}.
33 | \item \code{token}: An Azure token object. If supplied, all authentication details will be inferred from this.
34 | }
35 |
36 | The \code{login()}, \code{push()} and \code{pull()} methods for this class call the \code{docker} commandline tool under the hood. This allows all the features supported by Docker to be available immediately, with a minimum of effort. Any calls to the \code{docker} tool will also contain the full commandline as the \code{cmdline} attribute of the (invisible) returned value; this allows scripts to be developed that can be run outside R.
37 | }
38 |
39 | \examples{
40 | \dontrun{
41 |
42 | reg <- docker_registry("myregistry")
43 |
44 | reg$list_repositories()
45 |
46 | # create an image from a Dockerfile in the current directory
47 | call_docker(c("build", "-t", "myimage", "."))
48 |
49 | # push the image
50 | reg$push("myimage")
51 |
52 | reg$get_image_manifest("myimage")
53 | reg$get_image_digest("myimage")
54 |
55 | }
56 | }
57 | \seealso{
58 | \link{acr}, \link{docker_registry}, \link{call_docker}
59 |
60 | \href{https://docs.docker.com/engine/reference/commandline/cli/}{Docker commandline reference}
61 |
62 | \href{https://docs.docker.com/registry/spec/api/}{Docker registry API}
63 | }
64 |
--------------------------------------------------------------------------------
/man/KubernetesCluster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/kubernetes_cluster.R
3 | \docType{class}
4 | \name{KubernetesCluster}
5 | \alias{KubernetesCluster}
6 | \title{Kubernetes cluster class}
7 | \description{
8 | Class representing a \href{https://kubernetes.io/docs/home/}{Kubernetes} cluster. Note that this class can be used to interface with any Docker registry that supports the HTTP V2 API, not just those created via the Azure Container Registry service. Use the \link{kubernetes_cluster} function to instantiate new objects of this class.
9 | }
10 | \section{Methods}{
11 |
12 | The following methods are available, in addition to those provided by the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class:
13 | \itemize{
14 | \item \code{new(...)}: Initialize a new registry object. See 'Initialization' below.
15 | \item \code{create_registry_secret(registry, secret_name, email)}: Provide authentication secret for a Docker registry. See 'Secrets' below.
16 | \item \code{delete_registry_secret(secret_name)}: Delete a registry authentication secret.
17 | \item \code{create(file, ...)}: Creates a deployment or service from a file, using \verb{kubectl create -f}.
18 | \item \code{get(type, ...)}: Get information about resources, using \verb{kubectl get}.
19 | \item \code{run(name, image, ...)}: Run an image using \verb{kubectl run --image}.
20 | \item \code{expose(name, type, file, ...)}: Expose a service using \verb{kubectl expose}. If the \code{file} argument is provided, read service information from there.
21 | \item \code{delete(type, name, file, ...)}: Delete a resource (deployment or service) using \verb{kubectl delete}. If the \code{file} argument is provided, read resource information from there.
22 | \item \code{apply(file, ...)}: Apply a configuration file, using \verb{kubectl apply -f}.
23 | \item \code{show_dashboard(port, ...)}: Display the cluster dashboard. By default, use local port 30000.
24 | \item \code{kubectl(cmd, ...)}: Run an arbitrary \code{kubectl} command on this cluster. Called by the other methods above.
25 | \item \code{helm(cmd, ...)}: Run a \code{helm} command on this cluster.
26 | }
27 | }
28 |
29 | \section{Initialization}{
30 |
31 | The \code{new()} method takes one argument: \code{config}, the name of the file containing the configuration details for the cluster. This should be a YAML or JSON file in the standard Kubernetes configuration format. Set this to NULL to use the default \verb{~/.kube/config} file.
32 | }
33 |
34 | \section{Secrets}{
35 |
36 | The recommended way to allow a cluster to authenticate with a Docker registry is to give its service principal the appropriate role-based access. However, you can also authenticate with a username and password. To do this, call the \code{create_registry_secret} method with the following arguments:
37 | \itemize{
38 | \item \code{registry}: An object of class either \link{acr} representing an Azure Container Registry service, or \link{DockerRegistry} representing the registry itself.
39 | \item \code{secret_name}: The name to give the secret. Defaults to the name of the registry server.
40 | \item \code{email}: The email address for the Docker registry.
41 | }
42 | }
43 |
44 | \section{Kubectl and helm}{
45 |
46 | The methods for this class call the \code{kubectl} and \code{helm} commandline tools, passing the \code{--config} option to specify the configuration information for the cluster. This allows all the features supported by Kubernetes to be available immediately and with a minimum of effort, although it does require that the tools be installed. The returned object from a call to \code{kubectl} or \code{helm} will contain the following components:
47 | \itemize{
48 | \item \code{status}: The exit status. If this is \code{NA}, then the process was killed and had no exit status.
49 | \item \code{stdout}: The standard output of the command, in a character scalar.
50 | \item \code{stderr}: The standard error of the command, in a character scalar.
51 | \item \code{timeout}: Whether the process was killed because of a timeout.
52 | \item \code{cmdline}: The command line.
53 | }
54 |
55 | The first four components are from \code{processx::run}; AzureContainers adds the last to make it easier to construct scripts that can be run outside R.
56 | }
57 |
58 | \examples{
59 | \dontrun{
60 |
61 | rg <- AzureRMR::get_azure_login()$
62 | get_subscription("subscription_id")$
63 | get_resource_group("rgname")
64 |
65 | # get the cluster endpoint
66 | kubclus <- rg$get_aks("mycluster")$get_cluster()
67 |
68 | # get registry authentication secret
69 | kubclus$create_registry_secret(rg$get_acr("myregistry"))
70 |
71 | # deploy a service
72 | kubclus$create("deployment.yaml")
73 |
74 | # deploy a service from an Internet URL
75 | kubclus$create("https://example.com/deployment.yaml")
76 |
77 | # can also supply the deployment parameters inline
78 | kubclus$create("
79 | apiVersion: extensions/v1beta1
80 | kind: Deployment
81 | metadata:
82 | name: model1
83 | spec:
84 | replicas: 1
85 | template:
86 | metadata:
87 | labels:
88 | app: model1
89 | spec:
90 | containers:
91 | - name: model1
92 | image: myregistry.azurecr.io/model1
93 | ports:
94 | - containerPort: 8000
95 | imagePullSecrets:
96 | - name: myregistry.azurecr.io
97 | ---
98 | apiVersion: v1
99 | kind: Service
100 | metadata:
101 | name: model1-svc
102 | spec:
103 | selector:
104 | app: model1
105 | type: LoadBalancer
106 | ports:
107 | - protocol: TCP
108 | port: 8000")
109 |
110 | # track status
111 | kubclus$get("deployment")
112 | kubclus$get("service")
113 |
114 | }
115 | }
116 | \seealso{
117 | \link{aks}, \link{call_kubectl}, \link{call_helm}
118 |
119 | \href{https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands}{Kubectl commandline reference}
120 | }
121 |
--------------------------------------------------------------------------------
/man/aci.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/az_container_instance.R
3 | \docType{class}
4 | \name{aci}
5 | \alias{aci}
6 | \alias{az_container_instance}
7 | \title{Azure Container Instance class}
8 | \description{
9 | Class representing an Azure Container Instance (ACI) resource.
10 | }
11 | \section{Methods}{
12 |
13 | The following methods are available, in addition to those provided by the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class:
14 | \itemize{
15 | \item \code{new(...)}: Initialize a new ACI object.
16 | \item \code{restart()}, \code{start()}: Start a stopped container. These methods are synonyms for each other.
17 | \item \code{stop()}: Stop a container.
18 | }
19 | }
20 |
21 | \section{Details}{
22 |
23 | Initializing a new object of this class can either retrieve an existing ACI resource, or create a new resource on the host. Generally, the best way to initialize an object is via the \code{get_aci}, \code{create_aci} or \code{list_acis} methods of the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class, which handle the details automatically.
24 | }
25 |
26 | \examples{
27 | \dontrun{
28 |
29 | rg <- AzureRMR::get_azure_login()$
30 | get_subscription("subscription_id")$
31 | get_resource_group("rgname")
32 |
33 | myaci <- rg$get_aci("mycontainer")
34 |
35 | myaci$stop()
36 | myaci$restart()
37 |
38 | }
39 | }
40 | \seealso{
41 | \link{acr}, \link{aks}
42 |
43 | \href{https://learn.microsoft.com/en-us/azure/container-instances/}{ACI documentation} and
44 | \href{https://learn.microsoft.com/en-us/rest/api/container-instances/}{API reference}
45 |
46 | \href{https://docs.docker.com/engine/reference/commandline/cli/}{Docker commandline reference}
47 | }
48 |
--------------------------------------------------------------------------------
/man/aci_utils.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/az_container_instance.R
3 | \name{aci_ports}
4 | \alias{aci_ports}
5 | \alias{aci_creds}
6 | \alias{get_aci_credentials_list}
7 | \title{Utilities for specifying ACI configuration information}
8 | \usage{
9 | aci_ports(port = c(80L, 443L), protocol = "TCP")
10 |
11 | aci_creds(server, username = NULL, password = NULL)
12 |
13 | get_aci_credentials_list(lst)
14 | }
15 | \arguments{
16 | \item{port, protocol}{For \code{aci_ports}, vectors of the port numbers and protocols to open for the instance.}
17 |
18 | \item{server, username, password}{For \code{aci_creds}, the authentication details for a Docker registry. See \link{docker_registry}.}
19 |
20 | \item{lst}{for \code{get_aci_credentials_list}, a list of objects.}
21 | }
22 | \description{
23 | Utilities for specifying ACI configuration information
24 | }
25 | \details{
26 | These are helper functions to be used in specifying the configuration for a container instance. Only \code{aci_ports} and \code{aci_creds} are meant to be called by the user; \code{get_aci_credentials_list} is exported to workaround namespacing issues on startup.
27 | }
28 | \seealso{
29 | \link{create_aci}, \link{aci}, \link{docker_registry}
30 | }
31 |
--------------------------------------------------------------------------------
/man/acr.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/az_container_registry.R
3 | \docType{class}
4 | \name{acr}
5 | \alias{acr}
6 | \alias{az_container_registry}
7 | \title{Azure Container Registry class}
8 | \description{
9 | Class representing an Azure Container Registry (ACR) resource. For working with the registry endpoint itself, including uploading and downloading images etc, see \link{docker_registry}.
10 | }
11 | \section{Methods}{
12 |
13 | The following methods are available, in addition to those provided by the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class:
14 | \itemize{
15 | \item \code{new(...)}: Initialize a new ACR object. See 'Details'.
16 | \item \code{add_role_assignment(principal, role, scope=NULL, ...)}: Adds a role for the specified principal. This is an override mainly to handle AKS objects, so that the Kubernetes cluster can be granted access to the registry. You can use the \code{...} arguments to supply authentication details for AzureGraph, which is used to retrieve the cluster service principal.
17 | \item \code{list_credentials}: Return the username and passwords for this registry. Only valid if the Admin user for the registry has been enabled.
18 | \item \code{list_policies}: Return the policies for this registry.
19 | \item \code{list_usages}: Return the usage for this registry.
20 | \item \code{get_docker_registry(username, password)}: Return an object representing the Docker registry endpoint.
21 | }
22 | }
23 |
24 | \section{Details}{
25 |
26 | Initializing a new object of this class can either retrieve an existing registry resource, or create a new registry on the host. Generally, the best way to initialize an object is via the \code{get_acr}, \code{create_acr} or \code{list_acrs} methods of the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class, which handle the details automatically.
27 |
28 | Note that this class is separate from the Docker registry itself. This class exposes methods for working with the Azure resource: listing credentials, updating resource tags, updating and deleting the resource, and so on.
29 |
30 | For working with the registry, including uploading and downloading images, updating tags, deleting layers and images etc, use the endpoint object generated with \code{get_docker_registry}. This method takes two optional arguments:
31 | \itemize{
32 | \item \code{username}: The username that Docker will use to authenticate with the registry.
33 | \item \code{password}: The password that Docker will use to authenticate with the registry.
34 | }
35 |
36 | By default, these arguments will be retrieved from the ACR resource. They will only exist if the resource was created with \code{admin_user_enabled=TRUE}. Currently AzureContainers does not support authentication methods other than a username/password combination.
37 | }
38 |
39 | \examples{
40 | \dontrun{
41 |
42 | rg <- AzureRMR::get_azure_login()$
43 | get_subscription("subscription_id")$
44 | get_resource_group("rgname")
45 |
46 | myacr <- rg$get_acr("myregistry")
47 |
48 | myacr$list_credentials()
49 | myacr$list_policies()
50 |
51 | # see who has push and pull access
52 | myacr$list_role_assignments()
53 |
54 | # grant a Kubernetes cluster pull access
55 | myaks <- rg$get_aks("myaks")
56 | myacr$add_role_assignment(myaks, "Acrpull")
57 |
58 | # get the registry endpoint (for interactive use)
59 | myacr$get_docker_registry()
60 |
61 | # get the registry endpoint (admin user account)
62 | myacr$get_docker_registry(as_admin=TRUE)
63 |
64 | }
65 | }
66 | \seealso{
67 | \link{create_acr}, \link{get_acr}, \link{delete_acr}, \link{list_acrs}
68 |
69 | \link{docker_registry} for interacting with the Docker registry endpoint
70 |
71 | \href{https://learn.microsoft.com/en-us/azure/container-registry/}{Azure Container Registry} and
72 | \href{https://learn.microsoft.com/en-us/rest/api/containerregistry/registries}{API reference}
73 | }
74 |
--------------------------------------------------------------------------------
/man/agent_pool.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/az_kubernetes_service.R
3 | \name{agent_pool}
4 | \alias{agent_pool}
5 | \title{Utility function for specifying Kubernetes agent pools}
6 | \usage{
7 | agent_pool(name, count, size = "Standard_DS2_v2", os = "Linux",
8 | disksize = 0, use_scaleset = TRUE, low_priority = FALSE,
9 | autoscale_nodes = FALSE, ...)
10 | }
11 | \arguments{
12 | \item{name}{The name(s) of the pool(s).}
13 |
14 | \item{count}{The number of nodes per pool.}
15 |
16 | \item{size}{The VM type (size) to use for the pool. To see a list of available VM sizes, use the \link{list_vm_sizes} method for the resource group or subscription classes.}
17 |
18 | \item{os}{The operating system to use for the pool. Can be "Linux" or "Windows".}
19 |
20 | \item{disksize}{The OS disk size in gigabytes for each node in the pool. A value of 0 means to use the default disk size for the VM type.}
21 |
22 | \item{use_scaleset}{Whether to use a VM scaleset instead of individual VMs for this pool. A scaleset offers greater flexibility than individual VMs, and is the recommended method of creating an agent pool.}
23 |
24 | \item{low_priority}{If this pool uses a scaleset, whether it should be made up of spot (low-priority) VMs. A spot VM pool is cheaper, but is subject to being evicted to make room for other, higher-priority workloads. Ignored if \code{use_scaleset=FALSE}.}
25 |
26 | \item{autoscale_nodes}{The cluster autoscaling parameters for the pool. To enable autoscaling, set this to a vector of 2 numbers giving the minimum and maximum size of the agent pool. Ignored if \code{use_scaleset=FALSE}.}
27 |
28 | \item{...}{Other named arguments, to be used as parameters for the agent pool.}
29 | }
30 | \value{
31 | An object of class \code{agent_pool}, suitable for passing to the \code{create_aks} constructor method.
32 | }
33 | \description{
34 | Utility function for specifying Kubernetes agent pools
35 | }
36 | \details{
37 | \code{agent_pool} is a convenience function to simplify the task of specifying the agent pool for a Kubernetes cluster.
38 | }
39 | \examples{
40 | # pool of 5 Linux GPU-enabled VMs
41 | agent_pool("pool1", 5, size="Standard_NC6s_v3")
42 |
43 | # pool of 3 Windows Server VMs, 500GB disk size each
44 | agent_pool("pool1", 3, os="Windows", disksize=500)
45 |
46 | # enable cluster autoscaling, with a minimum of 1 and maximum of 10 nodes
47 | agent_pool("pool1", 5, autoscale_nodes=c(1, 10))
48 |
49 | # use individual VMs rather than scaleset
50 | agent_pool("vmpool1", 3, use_scaleset=FALSE)
51 |
52 | }
53 | \seealso{
54 | \link{create_aks}, \link{list_vm_sizes}
55 |
56 | \href{https://learn.microsoft.com/en-us/rest/api/aks/managedclusters/createorupdate#managedclusteragentpoolprofile}{Agent pool parameters on Microsoft Docs}
57 | }
58 |
--------------------------------------------------------------------------------
/man/aks.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/az_kubernetes_service.R
3 | \docType{class}
4 | \name{aks}
5 | \alias{aks}
6 | \alias{az_kubernetes_service}
7 | \title{Azure Kubernetes Service class}
8 | \description{
9 | Class representing an Azure Kubernetes Service (AKS) resource. For working with the cluster endpoint itself, including deploying images, creating services etc, see \link{kubernetes_cluster}.
10 | }
11 | \section{Methods}{
12 |
13 | The following methods are available, in addition to those provided by the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class:
14 | \itemize{
15 | \item \code{new(...)}: Initialize a new AKS object.
16 | \item \code{get_cluster(config, role)}: Return an object representing the Docker registry endpoint.
17 | \item \code{get_agent_pool(pollname)}: Returns an object of class \code{az_agent_pool} representing an agent pool. This class inherits from \link[AzureRMR:az_resource]{AzureRMR::az_resource}; it currently has no extra methods, but these may be added in the future.
18 | \item \code{list_agent_pools()}: Returns a list of agent pool objects.
19 | \item \code{create_agent_pool(poolname, ..., wait=FALSE)}: Creates a new agent pool. See the \link{agent_pool} function for further arguments to this method.
20 | \item \verb{delete_agent_pool(poolname, confirm=TRUE. wait=FALSE)}: Deletes an agent pool.
21 | \item \code{list_cluster_resources()}: Returns a list of all the Azure resources managed by the cluster.
22 | \item \code{update_aad_password(name=NULL, duration=NULL, ...)}: Update the password for Azure Active Directory integration, returning the new password invisibly. See 'Updating credentials' below.
23 | \item \code{update_service_password(name=NULL, duration=NULL, ...)}: Update the password for the service principal used to manage the cluster resources, returning the new password invisibly. See 'Updating credentials' below.
24 | }
25 | }
26 |
27 | \section{Details}{
28 |
29 | Initializing a new object of this class can either retrieve an existing AKS resource, or create a new resource on the host. Generally, the best way to initialize an object is via the \code{get_aks}, \code{create_aks} or \code{list_aks} methods of the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class, which handle the details automatically.
30 |
31 | Note that this class is separate from the Kubernetes cluster itself. This class exposes methods for working with the Azure resource: updating resource tags, updating and deleting the resource (including updating the Kubernetes version), and so on.
32 |
33 | For working with the cluster, including deploying images, services, etc use the object generated with the \code{get_cluster} method. This method takes two optional arguments:
34 | \itemize{
35 | \item \code{config}: The file in which to store the cluster configuration details. By default, this will be located in the AzureR configuration directory if it exists (see \link[AzureAuth:AzureR_dir]{AzureAuth::AzureR_dir}); otherwise, in the R temporary directory. To use the Kubernetes default \verb{~/.kube/config} file, set this argument to NULL. Any existing file in the given location will be overwritten.
36 | \item \code{role}: This can be \code{"User"} (the default) or \code{"Admin"}.
37 | }
38 | }
39 |
40 | \section{Updating credentials}{
41 |
42 | An AKS resource can have up to three service principals associated with it. Two of these are for Azure Active Directory (AAD) integration. The third is used to manage the subsidiary resources (VMs, networks, disks, etc) used by the cluster, if it doesn't have a service identity.
43 |
44 | Any service principals used by the AKS resource will have secret passwords, which have to be refreshed as they expire. The \code{update_aad_password()} and \code{update_service_password()} methods let you refresh the passwords for the cluster's service principals. Their arguments are:
45 | \itemize{
46 | \item \code{name}: An optional friendly name for the password.
47 | \item \code{duration}: The duration for which the new password is valid. Defaults to 2 years.
48 | \item \code{...}: Other arguments passed to \code{AzureGraph::create_graph_login}. Note that these are used to authenticate with Microsoft Graph, which does the actual work of updating the service principals, not to the cluster itself.
49 | }
50 | }
51 |
52 | \examples{
53 | \dontrun{
54 |
55 | rg <- AzureRMR::get_azure_login()$
56 | get_subscription("subscription_id")$
57 | get_resource_group("rgname")
58 |
59 | myaks <- rg$get_aks("mycluster")
60 |
61 | # sync with Azure: AKS resource creation can take a long time, use this to track status
62 | myaks$sync_fields()
63 |
64 | # get the cluster endpoint
65 | kubclus <- myaks$get_cluster()
66 |
67 | # list of agent pools
68 | myaks$list_agent_pools()
69 |
70 | # create a new agent pool, then delete it
71 | pool <- myaks$create_agent_pool("pool2", 3, size="Standard_DS3_v2")
72 | pool$delete()
73 |
74 | # refresh the service principal password (mostly for legacy clusters without a managed identity)
75 | myaks$update_service_password()
76 |
77 | # refresh the service principal password, using custom credentials to authenticate with MS Graph
78 | # arguments here are for Graph, not AKS!
79 | myaks$update_service_password(app="app_id", password="app_password")
80 |
81 | }
82 | }
83 | \seealso{
84 | \link{create_aks}, \link{get_aks}, \link{delete_aks}, \link{list_aks}, \link[AzureAuth:AzureR_dir]{AzureAuth::AzureR_dir}, \link[AzureGraph:graph_login]{AzureGraph::create_graph_login}
85 |
86 | \link{kubernetes_cluster} for interacting with the cluster endpoint
87 |
88 | \href{https://learn.microsoft.com/en-us/azure/aks/}{AKS documentation} and
89 | \href{https://learn.microsoft.com/en-us/rest/api/aks/}{API reference}
90 | }
91 |
--------------------------------------------------------------------------------
/man/aks_pools.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/az_kubernetes_service.R
3 | \name{aks_pools}
4 | \alias{aks_pools}
5 | \title{Vectorised utility function for specifying Kubernetes agent pools}
6 | \usage{
7 | aks_pools(name, count, size = "Standard_DS2_v2", os = "Linux")
8 | }
9 | \arguments{
10 | \item{name}{The name(s) of the pool(s).}
11 |
12 | \item{count}{The number of nodes per pool.}
13 |
14 | \item{size}{The VM type (size) to use for the pool. To see a list of available VM sizes, use the \link{list_vm_sizes} method for the resource group or subscription classes.}
15 |
16 | \item{os}{The operating system to use for the pool. Can be "Linux" or "Windows".}
17 | }
18 | \value{
19 | A list of lists, suitable for passing to the \code{create_aks} constructor method.
20 | }
21 | \description{
22 | Vectorised utility function for specifying Kubernetes agent pools
23 | }
24 | \details{
25 | This is a convenience function to simplify the task of specifying the agent pool for a Kubernetes cluster. You can specify multiple pools by providing vectors as input arguments; any scalar inputs will be replicated to match.
26 |
27 | \code{aks_pools} is deprecated; please use \link{agent_pool} going forward.
28 | }
29 | \examples{
30 | # 1 pool of 5 Linux VMs
31 | aks_pools("pool1", 5)
32 |
33 | # 1 pool of 3 Windows Server VMs
34 | aks_pools("pool1", 3, os="Windows")
35 |
36 | # 2 pools with different VM sizes per pool
37 | aks_pools(c("pool1", "pool2"), count=c(3, 3), size=c("Standard_DS2_v2", "Standard_DS3_v2"))
38 |
39 | }
40 | \seealso{
41 | \link{list_vm_sizes}, \link{agent_pool}
42 | }
43 |
--------------------------------------------------------------------------------
/man/call_docker.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ext_tools.R
3 | \name{call_docker}
4 | \alias{call_docker}
5 | \title{Call the docker commandline tool}
6 | \usage{
7 | call_docker(cmd = "", ..., echo = getOption("azure_containers_tool_echo",
8 | TRUE))
9 | }
10 | \arguments{
11 | \item{cmd}{The docker command. This should be a \emph{vector} of individual docker arguments, but can also be a single commandline string. See below.}
12 |
13 | \item{...}{Other arguments to pass to \link[processx:run]{processx::run}.}
14 |
15 | \item{echo}{Whether to echo the output of the command to the console.}
16 | }
17 | \value{
18 | A list with the following components:
19 | \itemize{
20 | \item \code{status}: The exit status of the docker tool. If this is \code{NA}, then the process was killed and had no exit status.
21 | \item \code{stdout}: The standard output of the command, in a character scalar.
22 | \item \code{stderr}: The standard error of the command, in a character scalar.
23 | \item \code{timeout}: Whether the process was killed because of a timeout.
24 | \item \code{cmdline}: The command line.
25 | }
26 |
27 | The first four components are from \code{processx::run}; AzureContainers adds the last to make it easier to construct scripts that can be run outside R.
28 | }
29 | \description{
30 | Call the docker commandline tool
31 | }
32 | \details{
33 | This function calls the \code{docker} binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
34 |
35 | The docker command should be specified as a vector of the individual arguments, which is what \code{processx::run} expects. If a single string is passed, for convenience and back-compatibility reasons \code{call_docker} will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
36 | }
37 | \examples{
38 | \dontrun{
39 |
40 | # without any args, prints the docker help screen
41 | call_docker()
42 |
43 | # build an image: recommended usage
44 | call_docker(c("build", "-t", "myimage", "."))
45 |
46 | # alternative usage, will be split into individual arguments
47 | call_docker("build -t myimage .")
48 |
49 | # list running containers
50 | call_docker(c("container", "ls"))
51 |
52 | # prune unused containers and images
53 | call_docker(c("container", "prune", "-f"))
54 | call_docker(c("image", "prune", "-f"))
55 |
56 | }
57 | }
58 | \seealso{
59 | \link[processx:run]{processx::run}, \link{call_docker_compose}, \link{call_kubectl} for the equivalent interface to the \code{kubectl} Kubernetes tool
60 |
61 | \link{docker_registry}
62 |
63 | \href{https://docs.docker.com/engine/reference/commandline/cli/}{Docker command line reference}
64 | }
65 |
--------------------------------------------------------------------------------
/man/call_docker_compose.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ext_tools.R
3 | \name{call_docker_compose}
4 | \alias{call_docker_compose}
5 | \title{Call the docker-compose commandline tool}
6 | \usage{
7 | call_docker_compose(cmd = "", ...,
8 | echo = getOption("azure_containers_tool_echo", TRUE))
9 | }
10 | \arguments{
11 | \item{cmd}{The docker-compose command line to execute. This should be a \emph{vector} of individual docker-compose arguments, but can also be a single commandline string. See below.}
12 |
13 | \item{...}{Other arguments to pass to \link[processx:run]{processx::run}.}
14 |
15 | \item{echo}{Whether to echo the output of the command to the console.}
16 | }
17 | \value{
18 | A list with the following components:
19 | \itemize{
20 | \item \code{status}: The exit status of the docker-compose tool. If this is \code{NA}, then the process was killed and had no exit status.
21 | \item \code{stdout}: The standard output of the command, in a character scalar.
22 | \item \code{stderr}: The standard error of the command, in a character scalar.
23 | \item \code{timeout}: Whether the process was killed because of a timeout.
24 | \item \code{cmdline}: The command line.
25 | }
26 |
27 | The first four components are from \code{processx::run}; AzureContainers adds the last to make it easier to construct scripts that can be run outside R.
28 | }
29 | \description{
30 | Call the docker-compose commandline tool
31 | }
32 | \details{
33 | This function calls the \code{docker-compose} binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
34 |
35 | The docker-compose command should be specified as a vector of the individual arguments, which is what \code{processx::run} expects. If a single string is passed, for convenience and back-compatibility reasons \code{call_docker_compose} will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
36 | }
37 | \seealso{
38 | \link[processx:run]{processx::run}, \link{call_docker}, \link{call_kubectl} for the equivalent interface to the \code{kubectl} Kubernetes tool
39 |
40 | \link{docker_registry}
41 |
42 | \href{https://docs.docker.com/compose/}{Docker-compose command line reference}
43 | }
44 |
--------------------------------------------------------------------------------
/man/call_helm.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ext_tools.R
3 | \name{call_helm}
4 | \alias{call_helm}
5 | \title{Call the Helm commandline tool}
6 | \usage{
7 | call_helm(cmd = "", config = NULL, ...,
8 | echo = getOption("azure_containers_tool_echo", TRUE))
9 | }
10 | \arguments{
11 | \item{cmd}{The Helm command line to execute. This should be a \emph{vector} of individual helm arguments, but can also be a single commandline string. See below.}
12 |
13 | \item{config}{The pathname of the cluster config file, if required.}
14 |
15 | \item{...}{Other arguments to pass to \link[processx:run]{processx::run}.}
16 |
17 | \item{echo}{Whether to echo the output of the command to the console.}
18 | }
19 | \value{
20 | A list with the following components:
21 | \itemize{
22 | \item \code{status}: The exit status of the helm tool. If this is \code{NA}, then the process was killed and had no exit status.
23 | \item \code{stdout}: The standard output of the command, in a character scalar.
24 | \item \code{stderr}: The standard error of the command, in a character scalar.
25 | \item \code{timeout}: Whether the process was killed because of a timeout.
26 | \item \code{cmdline}: The command line.
27 | }
28 |
29 | The first four components are from \code{processx::run}; AzureContainers adds the last to make it easier to construct scripts that can be run outside R.
30 | }
31 | \description{
32 | Call the Helm commandline tool
33 | }
34 | \details{
35 | This function calls the \code{helm} binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
36 |
37 | The helm command should be specified as a vector of the individual arguments, which is what \code{processx::run} expects. If a single string is passed, for convenience and back-compatibility reasons \code{call_docker_compose} will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
38 | }
39 | \seealso{
40 | \link[processx:run]{processx::run}, \link{call_docker}, \link{call_kubectl}
41 |
42 | \link{kubernetes_cluster}
43 |
44 | \href{https://kubernetes.io/docs/reference/kubectl/overview/}{Kubectl command line reference}
45 | }
46 |
--------------------------------------------------------------------------------
/man/call_kubectl.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ext_tools.R
3 | \name{call_kubectl}
4 | \alias{call_kubectl}
5 | \title{Call the Kubernetes commandline tool, kubectl}
6 | \usage{
7 | call_kubectl(cmd = "", config = NULL, ...,
8 | echo = getOption("azure_containers_tool_echo", TRUE))
9 | }
10 | \arguments{
11 | \item{cmd}{The kubectl command line to execute. This should be a \emph{vector} of individual kubectl arguments, but can also be a single commandline string. See below.}
12 |
13 | \item{config}{The pathname of the cluster config file, if required.}
14 |
15 | \item{...}{Other arguments to pass to \link[processx:run]{processx::run}.}
16 |
17 | \item{echo}{Whether to echo the output of the command to the console.}
18 | }
19 | \value{
20 | A list with the following components:
21 | \itemize{
22 | \item \code{status}: The exit status of the kubectl tool. If this is \code{NA}, then the process was killed and had no exit status.
23 | \item \code{stdout}: The standard output of the command, in a character scalar.
24 | \item \code{stderr}: The standard error of the command, in a character scalar.
25 | \item \code{timeout}: Whether the process was killed because of a timeout.
26 | \item \code{cmdline}: The command line.
27 | }
28 |
29 | The first four components are from \code{processx::run}; AzureContainers adds the last to make it easier to construct scripts that can be run outside R.
30 | }
31 | \description{
32 | Call the Kubernetes commandline tool, kubectl
33 | }
34 | \details{
35 | This function calls the \code{kubectl} binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
36 |
37 | The kubectl command should be specified as a vector of the individual arguments, which is what \code{processx::run} expects. If a single string is passed, for convenience and back-compatibility reasons \code{call_docker_compose} will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
38 | }
39 | \examples{
40 | \dontrun{
41 |
42 | # without any args, prints the kubectl help screen
43 | call_kubectl()
44 |
45 | # append "--help" to get help for a command
46 | call_kubectl(c("create", "--help"))
47 |
48 | # deploy a service from a yaml file
49 | call_kubectl(c("create", "-f", "deployment.yaml"))
50 |
51 | # get deployment and service status
52 | call_kubectl(c("get", "deployment"))
53 | call_kubectl(c("get", "service"))
54 |
55 | }
56 | }
57 | \seealso{
58 | \link[processx:run]{processx::run}, \link{call_docker}, \link{call_helm}
59 |
60 | \link{kubernetes_cluster}
61 |
62 | \href{https://kubernetes.io/docs/reference/kubectl/overview/}{Kubectl command line reference}
63 | }
64 |
--------------------------------------------------------------------------------
/man/create_aci.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_aci_methods.R
3 | \name{create_aci}
4 | \alias{create_aci}
5 | \title{Create Azure Container Instance (ACI)}
6 | \description{
7 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
8 | }
9 | \section{Usage}{
10 |
11 |
12 | \if{html}{\out{}}\preformatted{create_aci(name, location = self$location,
13 | container = name, image,
14 | registry_creds = list(),
15 | cores = 1, memory = 8,
16 | os = c("Linux", "Windows"),
17 | command = list(), env_vars = list(),
18 | ports = aci_ports(), dns_name = name, public_ip = TRUE,
19 | restart = c("Always", "OnFailure", "Never"), managed_identity = TRUE,
20 | ...)
21 | }\if{html}{\out{
}}
22 | }
23 |
24 | \section{Arguments}{
25 |
26 | \itemize{
27 | \item \code{name}: The name of the ACI service.
28 | \item \code{location}: The location/region in which to create the ACI service. Defaults to this resource group's location.
29 | \item \code{container}: The name of the running container.
30 | \item \code{image}: The name of the image to run.
31 | \item \code{registry_creds}: Docker registry authentication credentials, if the image is stored in a private registry. See 'Details'.
32 | \item \code{cores}: The number of CPU cores for the instance.
33 | \item \code{memory}: The memory size in GB for the instance.
34 | \item \code{os}: The operating system to run in the instance.
35 | \item \code{command}: A list of commands to run in the instance. This is similar to the \code{--entrypoint} commandline argument to \verb{docker run}; see \href{https://learn.microsoft.com/en-us/azure/container-instances/container-instances-start-command}{here} for some examples.
36 | \item \code{env_vars}: A list of name-value pairs to set as environment variables in the instance.
37 | \item \code{secure_env_vars}: A list of name-value pairs to set as \emph{secure} environment variables in the instance. The values of these variables are not visible in the container's properties, eg when viewed in the Azure portal or via the CLI.
38 | \item \code{ports}: The network ports to open. By default, opens ports 80 and 443. See 'Details'.
39 | \item \code{dns_name}: The domain name prefix for the instance. Only takes effect if \code{public_ip=TRUE}.
40 | \item \code{public_ip}: Whether the instance should be publicly accessible.
41 | \item \code{restart}: Whether to restart the instance should an event occur.
42 | \item \code{managed_identity}: Whether to assign the container instance a managed identity.
43 | \item \code{...}: Other named arguments to pass to the \link[AzureRMR:az_resource]{AzureRMR::az_resource} initialization function.
44 | }
45 | }
46 |
47 | \section{Details}{
48 |
49 | An ACI resource is a running container hosted in Azure. See the \href{https://learn.microsoft.com/en-us/azure/container-instances/}{documentation for the resource} for more information. Currently ACI only supports a single image in an instance.
50 |
51 | To supply the registry authentication credentials, the \code{registry_creds} argument should contain either an \link[=acr]{ACR} object, a \link{docker_registry} object, or the result of a call to the \link{aci_creds} function.
52 |
53 | The ports to open should be obtained by calling the \link{aci_ports} function. This takes a vector of port numbers as well as the protocol (TCP or UDP) for each port.
54 | }
55 |
56 | \section{Value}{
57 |
58 | An object of class \code{az_container_instance} representing the instance.
59 | }
60 |
61 | \examples{
62 | \dontrun{
63 |
64 | rg <- AzureRMR::get_azure_login()$
65 | get_subscription("subscription_id")$
66 | get_resource_group("rgname")
67 |
68 | # get the ACR resource that contains the image
69 | myacr <- rg$get_acr("myregistry", as_admin=TRUE)
70 |
71 | rg$create_aci("mycontainer",
72 | image="myregistry.azurecr.io/myimage:latest",
73 | registry_creds=myacr)
74 |
75 | }
76 | }
77 | \seealso{
78 | \link{get_aci}, \link{delete_aci}, \link{list_acis}
79 |
80 | \link{az_container_instance}
81 |
82 | \href{https://learn.microsoft.com/en-us/azure/container-instances/}{ACI documentation} and
83 | \href{https://learn.microsoft.com/en-us/rest/api/container-instances/}{API reference}
84 |
85 | \href{https://docs.docker.com/engine/reference/commandline/cli/}{Docker commandline reference}
86 | }
87 |
--------------------------------------------------------------------------------
/man/create_acr.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_acr_methods.R
3 | \name{create_acr}
4 | \alias{create_acr}
5 | \title{Create Azure Container Registry (ACR)}
6 | \description{
7 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
8 | }
9 | \section{Usage}{
10 |
11 |
12 | \if{html}{\out{}}\preformatted{create_acr(name, location = self$location,
13 | admin_user_enabled = TRUE, sku = "Standard", ...)
14 | }\if{html}{\out{
}}
15 | }
16 |
17 | \section{Arguments}{
18 |
19 | \itemize{
20 | \item \code{name}: The name of the container registry.
21 | \item \code{location}: The location/region in which to create the container registry. Defaults to this resource group's location.
22 | \item \code{admin_user_enabled}: Whether to enable the Admin user. Currently this must be \code{TRUE} for ACI to pull from the registry.
23 | \item \code{sku}: Either "Basic", "Standard" (the default) or "Premium".
24 | \item \code{wait}: Whether to wait until the ACR resource provisioning is complete.
25 | \item \code{...}: Other named arguments to pass to the \link[AzureRMR:az_resource]{AzureRMR::az_resource} initialization function.
26 | }
27 | }
28 |
29 | \section{Details}{
30 |
31 | An ACR resource is a Docker registry hosted in Azure. See the \href{https://learn.microsoft.com/en-us/azure/container-registry/}{documentation for the resource} for more information. To work with the registry (transfer images, retag images, etc) see the \link[=docker_registry]{documentation for the registry endpoint}.
32 | }
33 |
34 | \section{Value}{
35 |
36 | An object of class \code{az_container_registry} representing the registry resource.
37 | }
38 |
39 | \examples{
40 | \dontrun{
41 |
42 | rg <- AzureRMR::get_azure_login()$
43 | get_subscription("subscription_id")$
44 | get_resource_group("rgname")
45 |
46 | rg$create_acr("myregistry")
47 |
48 | }
49 | }
50 | \seealso{
51 | \link{get_acr}, \link{delete_acr}, \link{list_acrs}
52 |
53 | \link{az_container_registry}
54 |
55 | \link{docker_registry} for the registry endpoint
56 |
57 | \href{https://learn.microsoft.com/en-us/azure/container-registry/}{ACR documentation} and
58 | \href{https://learn.microsoft.com/en-us/rest/api/containerregistry/registries}{API reference}
59 |
60 | \href{https://docs.docker.com/registry/spec/api/}{Docker registry API}
61 | }
62 |
--------------------------------------------------------------------------------
/man/create_aks.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_aks_methods.R
3 | \name{create_aks}
4 | \alias{create_aks}
5 | \title{Create Azure Kubernetes Service (AKS)}
6 | \description{
7 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
8 | }
9 | \section{Usage}{
10 |
11 |
12 | \if{html}{\out{}}\preformatted{create_aks(name, location = self$location,
13 | dns_prefix = name, kubernetes_version = NULL,
14 | enable_rbac = FALSE, agent_pools = agent_pool("pool1", 3),
15 | login_user = "", login_passkey = "",
16 | cluster_service_principal = NULL, managed_identity = TRUE,
17 | private_cluster = FALSE,
18 | properties = list(), ..., wait = TRUE)
19 | }\if{html}{\out{
}}
20 | }
21 |
22 | \section{Arguments}{
23 |
24 | \itemize{
25 | \item \code{name}: The name of the Kubernetes service.
26 | \item \code{location}: The location/region in which to create the service. Defaults to this resource group's location.
27 | \item \code{dns_prefix}: The domain name prefix to use for the cluster endpoint. The actual domain name will start with this argument, followed by a string of pseudorandom characters.
28 | \item \code{kubernetes_version}: The Kubernetes version to use. If not specified, uses the most recent version of Kubernetes available.
29 | \item \code{enable_rbac}: Whether to enable Kubernetes role-based access controls (which is distinct from Azure AD RBAC).
30 | \item \code{agent_pools}: The pool specification(s) for the cluster. See 'Details'.
31 | \item \verb{login_user,login_passkey}: Optionally, a login username and public key (on Linux). Specify these if you want to be able to ssh into the cluster nodes.
32 | \item \code{cluster_service_principal}: The service principal that AKS will use to manage the cluster resources. This should be a list, with the first component being the client ID and the second the client secret. If not supplied, a new service principal will be created (requires an interactive session). Ignored if \code{managed_identity=TRUE}, which is the default.
33 | \item \code{managed_identity}: Whether the cluster should have a managed identity assigned to it. If \code{FALSE}, a service principal will be used to manage the cluster's resources; see 'Details' below.
34 | \item \code{private_cluster}: Whether this cluster is private (not visible from the public Internet). A private cluster is accessible only to hosts on its virtual network.
35 | \item \code{properties}: A named list of further Kubernetes-specific properties to pass to the initialization function.
36 | \item \code{wait}: Whether to wait until the AKS resource provisioning is complete. Note that provisioning a Kubernetes cluster can take several minutes.
37 | \item \code{...}: Other named arguments to pass to the initialization function.
38 | }
39 | }
40 |
41 | \section{Details}{
42 |
43 | An AKS resource is a Kubernetes cluster hosted in Azure. See the \link[=aks]{documentation for the resource} for more information. To work with the cluster (deploy images, define and start services, etc) see the \link[=kubernetes_cluster]{documentation for the cluster endpoint}.
44 |
45 | The nodes for an AKS cluster are organised into \emph{agent pools}, also known as \emph{node pools}, which are homogenous groups of virtual machines. To specify the details for a single agent pool, use the \code{agent_pool} function, which returns an S3 object of that class. To specify the details for multiple pools, you can supply a list of such objects, or a single call to the \code{aks_pools} function; see the examples below. Note that \code{aks_pools} is older, and does not support all the possible parameters for an agent pool.
46 |
47 | Of the agent pools in a cluster, at least one must be a \emph{system pool}, which is used to host critical system pods such as CoreDNS and tunnelfront. If you specify more than one pool, the first pool will be treated as the system pool. Note that there are certain \href{https://learn.microsoft.com/en-us/azure/aks/use-system-pools}{extra requirements} for the system pool.
48 |
49 | An AKS cluster requires an identity to manage the low-level resources it uses, such as virtual machines and networks. The default and recommended method is to use a \emph{managed identity}, in which all the details of this process are handled by AKS. In AzureContainers version 1.2.1 and older, a \emph{service principal} was used instead, which is an older and less automated method. By setting \code{managed_identity=FALSE}, you can continue using a service principal instead of a managed identity.
50 |
51 | One thing to be aware of with service principals is that they have a secret password that will expire eventually. By default, the password for a newly-created service principal will expire after one year. You should run the \code{update_service_password} method of the AKS object to reset/update the password before it expires.
52 | }
53 |
54 | \section{Value}{
55 |
56 | An object of class \code{az_kubernetes_service} representing the service.
57 | }
58 |
59 | \examples{
60 | \dontrun{
61 |
62 | rg <- AzureRMR::get_azure_login()$
63 | get_subscription("subscription_id")$
64 | get_resource_group("rgname")
65 |
66 | rg$create_aks("mycluster", agent_pools=agent_pool("pool1", 5))
67 |
68 | # GPU-enabled cluster
69 | rg$create_aks("mygpucluster", agent_pools=agent_pool("pool1", 5, size="Standard_NC6s_v3"))
70 |
71 | # multiple agent pools
72 | rg$create_aks("mycluster", agent_pools=list(
73 | agent_pool("pool1", 2),
74 | agent_pool("pool2", 3, size="Standard_NC6s_v3")
75 | ))
76 |
77 | # deprecated alternative for multiple pools
78 | rg$create_aks("mycluster",
79 | agent_pools=aks_pools(c("pool1", "pool2"), c(2, 3), c("Standard_DS2_v2", "Standard_NC6s_v3")))
80 |
81 | }
82 | }
83 | \seealso{
84 | \link{get_aks}, \link{delete_aks}, \link{list_aks}, \link{agent_pool}, \link{aks_pools}
85 |
86 | \link{az_kubernetes_service}
87 |
88 | \link{kubernetes_cluster} for the cluster endpoint
89 |
90 | \href{https://learn.microsoft.com/en-us/azure/aks/}{AKS documentation} and
91 | \href{https://learn.microsoft.com/en-us/rest/api/aks/}{API reference}
92 |
93 | \href{https://kubernetes.io/docs/reference/}{Kubernetes reference}
94 | }
95 |
--------------------------------------------------------------------------------
/man/delete_aci.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_aci_methods.R
3 | \name{delete_aci}
4 | \alias{delete_aci}
5 | \title{Delete an Azure Container Instance (ACI)}
6 | \description{
7 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
8 | }
9 | \section{Usage}{
10 |
11 |
12 | \if{html}{\out{}}\preformatted{delete_aci(name, confirm=TRUE, wait=FALSE)
13 | }\if{html}{\out{
}}
14 | }
15 |
16 | \section{Arguments}{
17 |
18 | \itemize{
19 | \item \code{name}: The name of the container instance.
20 | \item \code{confirm}: Whether to ask for confirmation before deleting.
21 | \item \code{wait}: Whether to wait until the deletion is complete.
22 | }
23 | }
24 |
25 | \section{Value}{
26 |
27 | NULL on successful deletion.
28 | }
29 |
30 | \examples{
31 | \dontrun{
32 |
33 | rg <- AzureRMR::get_azure_login()$
34 | get_subscription("subscription_id")$
35 | get_resource_group("rgname")
36 |
37 | rg$delete_aci("mycontainer")
38 |
39 | }
40 | }
41 | \seealso{
42 | \link{create_aci}, \link{get_aci}
43 |
44 | \link{az_container_instance}
45 |
46 | \href{https://learn.microsoft.com/en-us/azure/container-instances/}{ACI documentation} and
47 | \href{https://learn.microsoft.com/en-us/rest/api/container-instances/}{API reference}
48 |
49 | \href{https://docs.docker.com/engine/reference/commandline/cli/}{Docker commandline reference}
50 | }
51 |
--------------------------------------------------------------------------------
/man/delete_acr.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_acr_methods.R
3 | \name{delete_acr}
4 | \alias{delete_acr}
5 | \title{Delete an Azure Container Registry (ACR)}
6 | \description{
7 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
8 | }
9 | \section{Usage}{
10 |
11 |
12 | \if{html}{\out{}}\preformatted{delete_acr(name, confirm=TRUE, wait=FALSE)
13 | }\if{html}{\out{
}}
14 | }
15 |
16 | \section{Arguments}{
17 |
18 | \itemize{
19 | \item \code{name}: The name of the container registry.
20 | \item \code{confirm}: Whether to ask for confirmation before deleting.
21 | \item \code{wait}: Whether to wait until the deletion is complete.
22 | }
23 | }
24 |
25 | \section{Value}{
26 |
27 | NULL on successful deletion.
28 | }
29 |
30 | \examples{
31 | \dontrun{
32 |
33 | rg <- AzureRMR::get_azure_login()$
34 | get_subscription("subscription_id")$
35 | get_resource_group("rgname")
36 |
37 | rg$delete_acr("myregistry")
38 |
39 | }
40 | }
41 | \seealso{
42 | \link{create_acr}, \link{get_acr}
43 |
44 | \link{az_container_registry}
45 |
46 | \link{docker_registry} for the registry endpoint
47 |
48 | \href{https://learn.microsoft.com/en-us/azure/container-registry/}{ACR documentation} and
49 | \href{https://learn.microsoft.com/en-us/rest/api/containerregistry/registries}{API reference}
50 |
51 | \href{https://docs.docker.com/registry/spec/api/}{Docker registry API}
52 | }
53 |
--------------------------------------------------------------------------------
/man/delete_aks.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_aks_methods.R
3 | \name{delete_aks}
4 | \alias{delete_aks}
5 | \title{Delete an Azure Kubernetes Service (AKS)}
6 | \description{
7 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
8 | }
9 | \section{Usage}{
10 |
11 |
12 | \if{html}{\out{}}\preformatted{delete_aks(name, confirm=TRUE, wait=FALSE)
13 | }\if{html}{\out{
}}
14 | }
15 |
16 | \section{Arguments}{
17 |
18 | \itemize{
19 | \item \code{name}: The name of the Kubernetes service.
20 | \item \code{confirm}: Whether to ask for confirmation before deleting.
21 | \item \code{wait}: Whether to wait until the deletion is complete.
22 | }
23 | }
24 |
25 | \section{Value}{
26 |
27 | NULL on successful deletion.
28 | }
29 |
30 | \examples{
31 | \dontrun{
32 |
33 | rg <- AzureRMR::get_azure_login()$
34 | get_subscription("subscription_id")$
35 | get_resource_group("rgname")
36 |
37 | rg$delete_aks("mycluster")
38 |
39 | }
40 | }
41 | \seealso{
42 | \link{create_aks}, \link{get_aks}
43 |
44 | \link{az_kubernetes_service}
45 |
46 | \link{kubernetes_cluster} for the cluster endpoint
47 |
48 | \href{https://learn.microsoft.com/en-us/azure/aks/}{AKS documentation} and
49 | \href{https://learn.microsoft.com/en-us/rest/api/aks/}{API reference}
50 |
51 | \href{https://kubernetes.io/docs/reference/}{Kubernetes reference}
52 | }
53 |
--------------------------------------------------------------------------------
/man/docker_registry.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/docker_registry.R
3 | \name{docker_registry}
4 | \alias{docker_registry}
5 | \title{Create a new Docker registry object}
6 | \usage{
7 | docker_registry(server, tenant = "common", username = NULL,
8 | password = NULL, app = .az_cli_app_id, ..., domain = "azurecr.io",
9 | token = NULL, login = TRUE)
10 | }
11 | \arguments{
12 | \item{server}{The registry server. This can be a URL ("https://myregistry.azurecr.io") or a domain name label ("myregistry"); if the latter, the value of the \code{domain} argument is appended to obtain the full hostname.}
13 |
14 | \item{tenant, username, password, app, ...}{Authentication arguments to \link[AzureAuth:get_azure_token]{AzureAuth::get_azure_token}. See 'Details' below.}
15 |
16 | \item{domain}{The default domain for the registry server.}
17 |
18 | \item{token}{An OAuth token, of class \link[AzureAuth:AzureToken]{AzureAuth::AzureToken}. If supplied, the authentication details for the registry will be inferred from this.}
19 |
20 | \item{login}{Whether to perform a local login (requires that you have Docker installed). This is necessary if you want to push or pull images.}
21 | }
22 | \value{
23 | An R6 object of class \code{DockerRegistry}.
24 | }
25 | \description{
26 | Create a new Docker registry object
27 | }
28 | \details{
29 | There are two ways to authenticate with an Azure Docker registry: via Azure Active Directory (AAD), or with a username and password. The latter is simpler, while the former is more complex but also more flexible and secure.
30 |
31 | The default method of authenticating is via AAD. Without any arguments, \code{docker_registry} will authenticate using the AAD credentials of the currently logged-in user. You can change this by supplying the appropriate arguments to \code{docker_registry}, which will be passed to \code{AzureAuth::get_azure_token}; alternatively, you can provide an existing token object.
32 |
33 | To authenticate via the admin user account, set \code{app=NULL} and supply the admin username and password in the corresponding arguments. Note that for this to work, the registry must have been created with the admin account enabled.
34 |
35 | Authenticating with a service principal can be done either indirectly via AAD, or via a username and password. See the examples below. The latter method is recommended, as it is both faster and allows easier interoperability with AKS and ACI.
36 | }
37 | \examples{
38 | \dontrun{
39 |
40 | # connect to the Docker registry 'myregistry.azurecr.io', authenticating as the current user
41 | docker_registry("myregistry")
42 |
43 | # same, but providing a full URL
44 | docker_registry("https://myregistry.azurecr.io")
45 |
46 | # authenticating via the admin account
47 | docker_registry("myregistry", username="admin", password="password", app=NULL)
48 |
49 | # authenticating with a service principal, method 1: recommended
50 | docker_registry("myregistry", username="app_id", password="client_creds", app=NULL)
51 |
52 | # authenticating with a service principal, method 2
53 | docker_registry("myregistry", app="app_id", password="client_creds")
54 |
55 | # authenticating from a managed service identity (MSI)
56 | token <- AzureAuth::get_managed_token("https://management.azure.com/")
57 | docker_registry("myregistry", token=token)
58 |
59 | # you can also interact with a registry outside Azure
60 | # note that some registry methods, and AAD authentication, may not work in this case
61 | docker_registry("https://hub.docker.com", username="mydockerid", password="password", app=NULL)
62 |
63 | }
64 | }
65 | \seealso{
66 | \link{DockerRegistry} for methods available for interacting with the registry, \link{call_docker}
67 |
68 | \link{kubernetes_cluster} for the corresponding function to create a Kubernetes cluster object
69 | }
70 |
--------------------------------------------------------------------------------
/man/figures/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudyr/AzureContainers/e1c3644eb2dd4e4167ad79d5816f1ef06a7011eb/man/figures/logo.png
--------------------------------------------------------------------------------
/man/get_aci.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_aci_methods.R
3 | \name{get_aci}
4 | \alias{get_aci}
5 | \alias{list_acis}
6 | \title{Get Azure Container Instance (ACI)}
7 | \description{
8 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
9 | }
10 | \section{Usage}{
11 |
12 |
13 | \if{html}{\out{}}\preformatted{get_aci(name)
14 | list_acis()
15 | }\if{html}{\out{
}}
16 | }
17 |
18 | \section{Arguments}{
19 |
20 | \itemize{
21 | \item \code{name}: For \code{get_aci()}, the name of the container instance resource.
22 | }
23 | }
24 |
25 | \section{Details}{
26 |
27 | The \code{AzureRMR::az_resource_group} class has both \code{get_aci()} and \code{list_acis()} methods, while the \code{AzureRMR::az_subscription} class only has the latter.
28 | }
29 |
30 | \section{Value}{
31 |
32 | For \code{get_aci()}, an object of class \code{az_container_instance} representing the instance resource.
33 |
34 | For \code{list_acis()}, a list of such objects.
35 | }
36 |
37 | \examples{
38 | \dontrun{
39 |
40 | rg <- AzureRMR::get_azure_login()$
41 | get_subscription("subscription_id")$
42 | get_resource_group("rgname")
43 |
44 | rg$get_aci("mycontainer")
45 |
46 | }
47 | }
48 | \seealso{
49 | \link{create_aci}, \link{delete_aci}
50 |
51 | \link{az_container_instance}
52 |
53 | \href{https://learn.microsoft.com/en-us/azure/container-instances/}{ACI documentation} and
54 | \href{https://learn.microsoft.com/en-us/rest/api/container-instances/}{API reference}
55 |
56 | \href{https://docs.docker.com/engine/reference/commandline/cli/}{Docker commandline reference}
57 | }
58 |
--------------------------------------------------------------------------------
/man/get_acr.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_acr_methods.R
3 | \name{get_acr}
4 | \alias{get_acr}
5 | \alias{list_acrs}
6 | \title{Get Azure Container Registry (ACR)}
7 | \description{
8 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
9 | }
10 | \section{Usage}{
11 |
12 |
13 | \if{html}{\out{}}\preformatted{get_acr(name)
14 | list_acrs()
15 | }\if{html}{\out{
}}
16 | }
17 |
18 | \section{Arguments}{
19 |
20 | \itemize{
21 | \item \code{name}: For \code{get_acr()}, the name of the container registry resource.
22 | }
23 | }
24 |
25 | \section{Details}{
26 |
27 | The \code{AzureRMR::az_resource_group} class has both \code{get_acr()} and \code{list_acrs()} methods, while the \code{AzureRMR::az_subscription} class only has the latter.
28 | }
29 |
30 | \section{Value}{
31 |
32 | For \code{get_acr()}, an object of class \code{az_container_registry} representing the registry resource.
33 |
34 | For \code{list_acrs()}, a list of such objects.
35 | }
36 |
37 | \examples{
38 | \dontrun{
39 |
40 | rg <- AzureRMR::get_azure_login()$
41 | get_subscription("subscription_id")$
42 | get_resource_group("rgname")
43 |
44 | rg$get_acr("myregistry")
45 |
46 | }
47 | }
48 | \seealso{
49 | \link{create_acr}, \link{delete_acr}
50 |
51 | \link{az_container_registry}
52 |
53 | \link{docker_registry} for the registry endpoint
54 |
55 | \href{https://learn.microsoft.com/en-us/azure/container-registry/}{ACR documentation} and
56 | \href{https://learn.microsoft.com/en-us/rest/api/containerregistry/registries}{API reference}
57 |
58 | \href{https://docs.docker.com/registry/spec/api/}{Docker registry API}
59 | }
60 |
--------------------------------------------------------------------------------
/man/get_aks.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_aks_methods.R
3 | \name{get_aks}
4 | \alias{get_aks}
5 | \alias{list_aks}
6 | \title{Get Azure Kubernetes Service (AKS)}
7 | \description{
8 | Method for the \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} class.
9 | }
10 | \section{Usage}{
11 |
12 |
13 | \if{html}{\out{}}\preformatted{get_aks(name)
14 | list_aks()
15 | }\if{html}{\out{
}}
16 | }
17 |
18 | \section{Arguments}{
19 |
20 | \itemize{
21 | \item \code{name}: For \code{get_aks()}, the name of the Kubernetes service.
22 | }
23 | }
24 |
25 | \section{Details}{
26 |
27 | The \code{AzureRMR::az_resource_group} class has both \code{get_aks()} and \code{list_aks()} methods, while the \code{AzureRMR::az_subscription} class only has the latter.
28 | }
29 |
30 | \section{Value}{
31 |
32 | For \code{get_aks()}, an object of class \code{az_kubernetes_service} representing the service.
33 |
34 | For \code{list_aks()}, a list of such objects.
35 | }
36 |
37 | \examples{
38 | \dontrun{
39 |
40 | rg <- AzureRMR::get_azure_login()$
41 | get_subscription("subscription_id")$
42 | get_resource_group("rgname")
43 |
44 | rg$get_aks("mycluster")
45 |
46 | }
47 | }
48 | \seealso{
49 | \link{create_aks}, \link{delete_aks}
50 |
51 | \link{az_kubernetes_service}
52 |
53 | \link{kubernetes_cluster} for the cluster endpoint
54 |
55 | \href{https://learn.microsoft.com/en-us/azure/aks/}{AKS documentation} and
56 | \href{https://learn.microsoft.com/en-us/rest/api/aks/}{API reference}
57 |
58 | \href{https://kubernetes.io/docs/reference/}{Kubernetes reference}
59 | }
60 |
--------------------------------------------------------------------------------
/man/is.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/is.R
3 | \name{is_acr}
4 | \alias{is_acr}
5 | \alias{is_aks}
6 | \alias{is_aci}
7 | \alias{is_docker_registry}
8 | \alias{is_kubernetes_cluster}
9 | \title{Utility functions to test whether an object is of the given class.}
10 | \usage{
11 | is_acr(object)
12 |
13 | is_aks(object)
14 |
15 | is_aci(object)
16 |
17 | is_docker_registry(object)
18 |
19 | is_kubernetes_cluster(object)
20 | }
21 | \arguments{
22 | \item{object}{An R object}
23 | }
24 | \value{
25 | TRUE or FALSE depending on whether the object is an R6 object of the specified class.
26 | }
27 | \description{
28 | Utility functions to test whether an object is of the given class.
29 | }
30 | \details{
31 | These functions are simple wrappers around \code{R6::is.R6} and \code{inherits}.
32 | }
33 |
--------------------------------------------------------------------------------
/man/kubernetes_cluster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/kubernetes_cluster.R
3 | \name{kubernetes_cluster}
4 | \alias{kubernetes_cluster}
5 | \title{Create a new Kubernetes cluster object}
6 | \usage{
7 | kubernetes_cluster(config = NULL)
8 | }
9 | \arguments{
10 | \item{config}{The name of the file containing the configuration details for the cluster. This should be a YAML or JSON file in the standard Kubernetes configuration format. Set this to NULL to use the default \verb{~/.kube/config} file.}
11 | }
12 | \value{
13 | An R6 object of class \code{KubernetesCluster}.
14 | }
15 | \description{
16 | Create a new Kubernetes cluster object
17 | }
18 | \details{
19 | Use this function to instantiate a new object of the \code{KubernetesCluster} class, for interacting with a Kubernetes cluster.
20 | }
21 | \examples{
22 | \dontrun{
23 |
24 | kubernetes_cluster()
25 | kubernetes_cluster("myconfig.yaml")
26 |
27 | }
28 | }
29 | \seealso{
30 | \link{KubernetesCluster} for methods for working with the cluster, \link{call_kubectl}, \link{call_helm}
31 |
32 | \link{docker_registry} for the corresponding function to create a Docker registry object
33 | }
34 |
--------------------------------------------------------------------------------
/man/list_kubernetes_versions.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_aks_methods.R
3 | \name{list_kubernetes_versions}
4 | \alias{list_kubernetes_versions}
5 | \title{List available Kubernetes versions}
6 | \description{
7 | Method for the \link[AzureRMR:az_subscription]{AzureRMR::az_subscription} and \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} classes.
8 | }
9 | \section{Usage}{
10 |
11 |
12 | \if{html}{\out{}}\preformatted{## R6 method for class 'az_subscription'
13 | list_kubernetes_versions(location)
14 |
15 | ## R6 method for class 'az_resource_group'
16 | list_kubernetes_versions()
17 | }\if{html}{\out{
}}
18 | }
19 |
20 | \section{Arguments}{
21 |
22 | \itemize{
23 | \item \code{location}: For the az_subscription class method, the location for which to obtain available Kubernetes versions.
24 | }
25 | }
26 |
27 | \section{Value}{
28 |
29 | A vector of strings, which are the Kubernetes versions that can be used when creating a cluster.
30 | }
31 |
32 | \examples{
33 | \dontrun{
34 |
35 | rg <- AzureRMR::get_azure_login()$
36 | get_subscription("subscription_id")$
37 | get_resource_group("rgname")
38 |
39 | rg$list_kubernetes_versions()
40 |
41 | }
42 | }
43 | \seealso{
44 | \link{create_aks}
45 |
46 | \href{https://kubernetes.io/docs/reference/}{Kubernetes reference}
47 | }
48 |
--------------------------------------------------------------------------------
/man/list_vm_sizes.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/add_vmsize_methods.R
3 | \name{list_vm_sizes}
4 | \alias{list_vm_sizes}
5 | \title{List available VM sizes}
6 | \description{
7 | Method for the \link[AzureRMR:az_subscription]{AzureRMR::az_subscription} and \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} classes.
8 | }
9 | \section{Usage}{
10 |
11 |
12 | \if{html}{\out{}}\preformatted{## R6 method for class 'az_subscription'
13 | list_vm_sizes(location, name_only = FALSE)
14 |
15 | ## R6 method for class 'az_resource_group'
16 | list_vm_sizes(name_only = FALSE)
17 | }\if{html}{\out{
}}
18 | }
19 |
20 | \section{Arguments}{
21 |
22 | \itemize{
23 | \item \code{location}: For the subscription class method, the location/region for which to obtain available VM sizes.
24 | \item \code{name_only}: Whether to return only a vector of names, or all information on each VM size.
25 | }
26 | }
27 |
28 | \section{Value}{
29 |
30 | If \code{name_only} is TRUE, a character vector of names. If FALSE, a data frame containing the following information for each VM size: the name, number of cores, OS disk size, resource disk size, memory, and maximum data disks.
31 | }
32 |
33 | \examples{
34 | \dontrun{
35 |
36 | sub <- AzureRMR::get_azure_login()$
37 | get_subscription("subscription_id")
38 |
39 | sub$list_vm_sizes("australiaeast")
40 |
41 | # same output as above
42 | rg <- sub$create_resource_group("rgname", location="australiaeast")
43 | rg$list_vm_sizes()
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/resources/hello.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: hellodep
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: hellodep
9 | replicas: 1
10 | template:
11 | metadata:
12 | labels:
13 | app: hellodep
14 | spec:
15 | containers:
16 | - name: acrname
17 | image: acrname.azurecr.io/hello-world
18 | imagePullSecrets:
19 | - name: acrname.azurecr.io
20 | ---
21 | apiVersion: v1
22 | kind: Service
23 | metadata:
24 | name: hellodep-svc
25 | spec:
26 | selector:
27 | app: hellodep
28 | type: LoadBalancer
29 | ports:
30 | - protocol: TCP
31 | port: 80
32 |
--------------------------------------------------------------------------------
/tests/resources/hello_dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine
2 |
3 |
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(AzureContainers)
3 |
4 | test_check("AzureContainers")
5 |
--------------------------------------------------------------------------------
/tests/testthat/setup.R:
--------------------------------------------------------------------------------
1 | make_name <- function(n=20)
2 | {
3 | paste0(sample(letters, n, TRUE), collapse="")
4 | }
5 |
--------------------------------------------------------------------------------
/tests/testthat/test00_tools.R:
--------------------------------------------------------------------------------
1 | context("Tools interface")
2 |
3 | if(.AzureContainers$docker == "" ||
4 | .AzureContainers$dockercompose == "" ||
5 | .AzureContainers$kubectl == "" ||
6 | .AzureContainers$helm == "")
7 | skip("Tests skipped: external tools not found")
8 |
9 | echo <- getOption("azure_containers_tool_echo")
10 | options(azure_containers_tool_echo=FALSE)
11 |
12 | test_that("Docker works",
13 | {
14 | cmd <- "--help"
15 | obj <- call_docker(cmd)
16 | expect_is(obj, "list")
17 | expect_true(grepl("docker --help", obj$cmdline, fixed=TRUE))
18 | })
19 |
20 | test_that("Docker compose works",
21 | {
22 | cmd <- "--help"
23 | obj <- call_docker_compose(cmd)
24 | expect_is(obj, "list")
25 | expect_true(grepl("docker-compose --help", obj$cmdline, fixed=TRUE))
26 | })
27 |
28 | test_that("Kubectl works",
29 | {
30 | cmd <- "--help"
31 | obj <- call_kubectl(cmd)
32 | expect_is(obj, "list")
33 | expect_true(grepl("kubectl --help", obj$cmdline, fixed=TRUE))
34 | })
35 |
36 | test_that("Helm works",
37 | {
38 | cmd <- "--help"
39 | obj <- call_helm(cmd)
40 | expect_is(obj, "list")
41 | expect_true(grepl("helm --help", obj$cmdline, fixed=TRUE))
42 | })
43 |
44 | teardown({
45 | options(azure_containers_tool_echo=echo)
46 | })
47 |
--------------------------------------------------------------------------------
/tests/testthat/test01_acr.R:
--------------------------------------------------------------------------------
1 | context("ACR interface")
2 |
3 | tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
4 | app <- Sys.getenv("AZ_TEST_APP_ID")
5 | password <- Sys.getenv("AZ_TEST_PASSWORD")
6 | subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
7 |
8 | if(tenant == "" || app == "" || password == "" || subscription == "")
9 | skip("Tests skipped: ARM credentials not set")
10 |
11 | rgname <- make_name(10)
12 | rg <- AzureRMR::az_rm$
13 | new(tenant=tenant, app=app, password=password)$
14 | get_subscription(subscription)$
15 | create_resource_group(rgname, location="australiaeast")
16 |
17 | echo <- getOption("azure_containers_tool_echo")
18 | options(azure_containers_tool_echo=FALSE)
19 |
20 | acrname <- make_name(10)
21 |
22 | test_that("ACR works",
23 | {
24 | expect_true(is_acr(rg$create_acr(acrname)))
25 | acr <- rg$get_acr(acrname)
26 | expect_true(is_acr(acr))
27 |
28 | acr2 <- rg$list_acrs()[[1]]
29 | expect_true(is_acr(acr2))
30 |
31 | reg <- acr$get_docker_registry()
32 | expect_true(is_docker_registry(reg))
33 |
34 | cmdline <- "build -f ../resources/hello_dockerfile -t hello-world ."
35 | output <- call_docker(cmdline)
36 | expect_equal(output$cmdline, paste("docker", cmdline))
37 |
38 | reg$push("hello-world")
39 |
40 | cmdline <- paste0("image rm ", acrname, ".azurecr.io/hello-world")
41 | call_docker(cmdline)
42 |
43 | expect_equal(reg$list_repositories(), "hello-world")
44 | })
45 |
46 | test_that("ACR works with app login",
47 | {
48 | acr <- rg$get_acr(acrname)
49 | expect_true(is_acr(acr))
50 |
51 | acr$add_role_assignment(
52 | principal=AzureGraph::get_graph_login(tenant)$get_app(app),
53 | role="owner"
54 | )
55 |
56 | reg <- acr$get_docker_registry(username=app, password=password, app=NULL)
57 | expect_true(is_docker_registry(reg))
58 | expect_identical(reg$username, app)
59 |
60 | cmdline <- "build -f ../resources/hello_dockerfile -t hello-world-sp ."
61 | output <- call_docker(cmdline)
62 | expect_equal(output$cmdline, paste("docker", cmdline))
63 |
64 | reg$push("hello-world-sp")
65 |
66 | cmdline <- paste0("image rm ", acrname, ".azurecr.io/hello-world-sp")
67 | call_docker(cmdline)
68 |
69 | expect_equal(reg$list_repositories(), c("hello-world", "hello-world-sp"))
70 | })
71 |
72 | teardown({
73 | options(azure_containers_tool_echo=echo)
74 | suppressMessages(rg$delete(confirm=FALSE))
75 | })
76 |
--------------------------------------------------------------------------------
/tests/testthat/test02_aci.R:
--------------------------------------------------------------------------------
1 | context("ACI interface")
2 |
3 | tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
4 | app <- Sys.getenv("AZ_TEST_APP_ID")
5 | password <- Sys.getenv("AZ_TEST_PASSWORD")
6 | subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
7 |
8 | if(tenant == "" || app == "" || password == "" || subscription == "")
9 | skip("Tests skipped: ARM credentials not set")
10 |
11 | rgname <- make_name(10)
12 | rg <- AzureRMR::az_rm$
13 | new(tenant=tenant, app=app, password=password)$
14 | get_subscription(subscription)$
15 | create_resource_group(rgname, location="australiaeast")
16 |
17 | echo <- getOption("azure_containers_tool_echo")
18 | options(azure_containers_tool_echo=FALSE)
19 |
20 | test_that("ACI works",
21 | {
22 | acrname <- make_name(10)
23 | acr <- rg$create_acr(acrname, admin_user_enabled=TRUE)
24 | reg <- acr$get_docker_registry(as_admin=TRUE)
25 | expect_true(is_docker_registry(reg))
26 | expect_false(is.null(reg$username) || is.null(reg$password))
27 |
28 | cmdline <- "build -f ../resources/hello_dockerfile -t hello-world ."
29 | call_docker(cmdline)
30 |
31 | reg$push("hello-world")
32 |
33 | cmdline <- paste0("image rm ", acrname, ".azurecr.io/hello-world")
34 | call_docker(cmdline)
35 |
36 | # from local image
37 | aciname <- make_name(10)
38 | expect_true(is_aci(rg$create_aci(aciname,
39 | image="hello-world",
40 | env_vars=list(MYVAR="myvalue")),
41 | secure_env_vars=list(MYSECUREVAR="mysecurevalue"),
42 | command=c("/bin/sh", "-c", "ls"))
43 | )
44 |
45 | aci <- rg$get_aci(aciname)
46 | expect_true(is_aci(aci))
47 | expect_true(is_aci(rg$list_acis()[[1]]))
48 |
49 | expect_silent(aci$stop())
50 | Sys.sleep(2)
51 | expect_silent(aci$start())
52 | Sys.sleep(2)
53 | expect_silent(aci$restart())
54 |
55 | # from Resource Manager object
56 | aciname2 <- make_name(10)
57 | aci2 <- rg$create_aci(aciname2,
58 | image=paste0(reg$server$hostname, "/hello-world"),
59 | registry_creds=reg)
60 |
61 | expect_true(is_aci(aci2))
62 |
63 | # from Docker registry object
64 | aciname3 <- make_name(10)
65 | aci3 <- rg$create_aci(aciname3,
66 | image=paste0(reg$server$hostname, "/hello-world"),
67 | registry_creds=aci_creds(reg$server$hostname, app, password))
68 |
69 | expect_true(is_aci(aci3))
70 | })
71 |
72 |
73 | teardown({
74 | options(azure_containers_tool_echo=echo)
75 | suppressMessages(rg$delete(confirm=FALSE))
76 | })
77 |
--------------------------------------------------------------------------------
/tests/testthat/test03a_aks_msi.R:
--------------------------------------------------------------------------------
1 | context("AKS interface with managed identity")
2 |
3 | tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
4 | app <- Sys.getenv("AZ_TEST_APP_ID")
5 | password <- Sys.getenv("AZ_TEST_PASSWORD")
6 | subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
7 |
8 | if(tenant == "" || app == "" || password == "" || subscription == "")
9 | skip("Tests skipped: ARM credentials not set")
10 |
11 | rgname <- make_name(10)
12 | rg <- AzureRMR::az_rm$
13 | new(tenant=tenant, app=app, password=password)$
14 | get_subscription(subscription)$
15 | create_resource_group(rgname, location="australiaeast")
16 |
17 | echo <- getOption("azure_containers_tool_echo")
18 | options(azure_containers_tool_echo=FALSE)
19 |
20 | test_that("AKS works with managed identity",
21 | {
22 | aksname <- make_name(10)
23 |
24 | expect_is(rg$list_kubernetes_versions(), "character")
25 |
26 | expect_true(is_aks(rg$create_aks(aksname, agent_pools=agent_pool("pool1", 1), managed_identity=TRUE)))
27 | expect_true(is_aks(rg$list_aks()[[1]]))
28 | aks <- rg$get_aks(aksname)
29 | expect_true(is_aks(aks))
30 |
31 | # no SP password with svc identity
32 | expect_error(aks$update_service_password())
33 |
34 | pool1 <- aks$get_agent_pool("pool1")
35 | expect_is(pool1, "az_agent_pool")
36 |
37 | pools <- aks$list_agent_pools()
38 | expect_true(is.list(pools) && length(pools) == 1 && all(sapply(pools, inherits, "az_agent_pool")))
39 |
40 | pool2 <- aks$create_agent_pool("pool2", 2, disksize=500, wait=TRUE, autoscale_nodes=c(1, 5))
41 | expect_is(pool2, "az_agent_pool")
42 | expect_true(pool2$properties$enableAutoScaling)
43 | expect_equal(pool2$properties$minCount, 1)
44 | expect_equal(pool2$properties$maxCount, 5)
45 |
46 | pools <- aks$list_agent_pools()
47 | expect_true(is.list(pools) && length(pools) == 2 && all(sapply(pools, inherits, "az_agent_pool")))
48 |
49 | expect_message(pool2$delete(confirm=FALSE))
50 |
51 | clus <- aks$get_cluster()
52 | expect_true(is_kubernetes_cluster(clus))
53 | })
54 |
55 |
56 | teardown({
57 | options(azure_containers_tool_echo=echo)
58 | suppressMessages(rg$delete(confirm=FALSE))
59 | })
60 |
--------------------------------------------------------------------------------
/tests/testthat/test03b_aks_acr_msi.R:
--------------------------------------------------------------------------------
1 | context("AKS-ACR interop with managed identity")
2 |
3 | tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
4 | app <- Sys.getenv("AZ_TEST_APP_ID")
5 | password <- Sys.getenv("AZ_TEST_PASSWORD")
6 | subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
7 |
8 | if(tenant == "" || app == "" || password == "" || subscription == "")
9 | skip("Tests skipped: ARM credentials not set")
10 |
11 | rgname <- make_name(10)
12 | rg <- AzureRMR::az_rm$
13 | new(tenant=tenant, app=app, password=password)$
14 | get_subscription(subscription)$
15 | create_resource_group(rgname, location="australiaeast")
16 |
17 | echo <- getOption("azure_containers_tool_echo")
18 | options(azure_containers_tool_echo=FALSE)
19 |
20 | aksname <- make_name(10)
21 | aks <- rg$create_aks(aksname, agent_pools=agent_pool("pool1", 1), managed_identity=TRUE)
22 |
23 | test_that("AKS/ACR works with managed identity",
24 | {
25 | acrname <- make_name(10)
26 | acr <- rg$create_acr(acrname, admin_user_enabled=TRUE)
27 | reg <- acr$get_docker_registry(as_admin=TRUE)
28 | expect_true(is_docker_registry(reg))
29 |
30 | cmdline <- "build -f ../resources/hello_dockerfile -t hello-world ."
31 | call_docker(cmdline)
32 |
33 | reg$push("hello-world")
34 |
35 | cmdline <- paste0("image rm ", acrname, ".azurecr.io/hello-world")
36 | call_docker(cmdline)
37 |
38 | expect_true(is_aks(aks))
39 |
40 | clus <- aks$get_cluster()
41 | expect_true(is_kubernetes_cluster(clus))
42 |
43 | hello_yaml <- gsub("acrname", acrname, readLines("../resources/hello.yaml"))
44 | clus$create_registry_secret(reg, email="me@example.com")
45 | clus$create(hello_yaml)
46 | })
47 |
48 |
49 | test_that("AKS/ACR works with managed identity/RBAC",
50 | {
51 | acrname <- make_name(10)
52 | acr <- rg$create_acr(acrname, admin_user_enabled=FALSE)
53 | reg <- acr$get_docker_registry(as_admin=FALSE)
54 | expect_true(is_docker_registry(reg))
55 |
56 | cmdline <- "build -f ../resources/hello_dockerfile -t hello-world ."
57 | call_docker(cmdline)
58 |
59 | reg$push("hello-world")
60 |
61 | cmdline <- paste0("image rm ", acrname, ".azurecr.io/hello-world")
62 | call_docker(cmdline)
63 |
64 | acr$add_role_assignment(aks, "Acrpull")
65 |
66 | clus <- aks$get_cluster()
67 | expect_true(is_kubernetes_cluster(clus))
68 |
69 | hello_yaml <- gsub("acrname", acrname, readLines("../resources/hello.yaml"))
70 | hello_yaml <- gsub("hellodep", "hellodep-rb", hello_yaml)
71 | clus$create(hello_yaml)
72 | })
73 |
74 |
75 | teardown({
76 | options(azure_containers_tool_echo=echo)
77 | suppressMessages(rg$delete(confirm=FALSE))
78 | })
79 |
--------------------------------------------------------------------------------
/tests/testthat/test03c_aks_sp.R:
--------------------------------------------------------------------------------
1 | context("AKS interface with service principal")
2 |
3 | tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
4 | app <- Sys.getenv("AZ_TEST_APP_ID")
5 | password <- Sys.getenv("AZ_TEST_PASSWORD")
6 | subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
7 |
8 | if(tenant == "" || app == "" || password == "" || subscription == "")
9 | skip("Tests skipped: ARM credentials not set")
10 |
11 | rgname <- make_name(10)
12 | rg <- AzureRMR::az_rm$
13 | new(tenant=tenant, app=app, password=password)$
14 | get_subscription(subscription)$
15 | create_resource_group(rgname, location="australiaeast")
16 |
17 | echo <- getOption("azure_containers_tool_echo")
18 | options(azure_containers_tool_echo=FALSE)
19 |
20 | test_that("AKS works with service principal",
21 | {
22 | aksname <- paste0(sample(letters, 10, TRUE), collapse="")
23 | expect_true(is_aks(rg$create_aks(aksname, agent_pools=agent_pool("pool1", 1), managed_identity=FALSE)))
24 | aks <- rg$get_aks(aksname)
25 | expect_true(is_aks(aks))
26 |
27 | expect_message(aks$update_service_password())
28 |
29 | pool1 <- aks$get_agent_pool("pool1")
30 | expect_is(pool1, "az_agent_pool")
31 |
32 | pools <- aks$list_agent_pools()
33 | expect_true(is.list(pools) && length(pools) == 1 && all(sapply(pools, inherits, "az_agent_pool")))
34 |
35 | pool2 <- aks$create_agent_pool("pool2", 1, disksize=500, wait=TRUE)
36 | expect_is(pool2, "az_agent_pool")
37 |
38 | pools <- aks$list_agent_pools()
39 | expect_true(is.list(pools) && length(pools) == 2 && all(sapply(pools, inherits, "az_agent_pool")))
40 |
41 | expect_message(pool2$delete(confirm=FALSE))
42 |
43 | clus <- aks$get_cluster()
44 | expect_true(is_kubernetes_cluster(clus))
45 | })
46 |
47 |
48 | teardown({
49 | options(azure_containers_tool_echo=echo)
50 | suppressMessages(rg$delete(confirm=FALSE))
51 | })
52 |
--------------------------------------------------------------------------------
/tests/testthat/test03d_aks_acr_sp.R:
--------------------------------------------------------------------------------
1 | context("AKS-ACR interop with service principal")
2 |
3 | tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
4 | app <- Sys.getenv("AZ_TEST_APP_ID")
5 | password <- Sys.getenv("AZ_TEST_PASSWORD")
6 | subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
7 |
8 | if(tenant == "" || app == "" || password == "" || subscription == "")
9 | skip("Tests skipped: ARM credentials not set")
10 |
11 | rgname <- make_name(10)
12 | rg <- AzureRMR::az_rm$
13 | new(tenant=tenant, app=app, password=password)$
14 | get_subscription(subscription)$
15 | create_resource_group(rgname, location="australiaeast")
16 |
17 | echo <- getOption("azure_containers_tool_echo")
18 | options(azure_containers_tool_echo=FALSE)
19 |
20 | aksname <- make_name(10)
21 | aks <- rg$create_aks(aksname, agent_pools=agent_pool("pool1", 1), managed_identity=FALSE)
22 |
23 | test_that("AKS/ACR works with service principal",
24 | {
25 | acrname <- make_name(10)
26 | acr <- rg$create_acr(acrname, admin_user_enabled=TRUE)
27 | reg <- acr$get_docker_registry(as_admin=TRUE)
28 | expect_true(is_docker_registry(reg))
29 |
30 | cmdline <- "build -f ../resources/hello_dockerfile -t hello-world ."
31 | call_docker(cmdline)
32 |
33 | reg$push("hello-world")
34 |
35 | cmdline <- paste0("image rm ", acrname, ".azurecr.io/hello-world")
36 | call_docker(cmdline)
37 |
38 | expect_true(is_aks(aks))
39 |
40 | clus <- aks$get_cluster()
41 | expect_true(is_kubernetes_cluster(clus))
42 |
43 | hello_yaml <- gsub("acrname", acrname, readLines("../resources/hello.yaml"))
44 | clus$create_registry_secret(reg, email="me@example.com")
45 | clus$create(hello_yaml)
46 | })
47 |
48 |
49 | test_that("AKS/ACR works with service principal/RBAC",
50 | {
51 | acrname <- make_name(10)
52 | acr <- rg$create_acr(acrname, admin_user_enabled=FALSE)
53 | reg <- acr$get_docker_registry(as_admin=FALSE)
54 | expect_true(is_docker_registry(reg))
55 |
56 | cmdline <- "build -f ../resources/hello_dockerfile -t hello-world ."
57 | call_docker(cmdline)
58 |
59 | reg$push("hello-world")
60 |
61 | cmdline <- paste0("image rm ", acrname, ".azurecr.io/hello-world")
62 | call_docker(cmdline)
63 |
64 | acr$add_role_assignment(aks, "Acrpull")
65 |
66 | clus <- aks$get_cluster()
67 | expect_true(is_kubernetes_cluster(clus))
68 |
69 | hello_yaml <- gsub("acrname", acrname, readLines("../resources/hello.yaml"))
70 | hello_yaml <- gsub("hellodep", "hellodep-rb", hello_yaml)
71 | clus$create(hello_yaml)
72 | })
73 |
74 |
75 | teardown({
76 | options(azure_containers_tool_echo=echo)
77 | suppressMessages(rg$delete(confirm=FALSE))
78 | })
79 |
--------------------------------------------------------------------------------
/tests/testthat/test03e_aks_oldnodes.R:
--------------------------------------------------------------------------------
1 | context("AKS interface with availability set")
2 |
3 | tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
4 | app <- Sys.getenv("AZ_TEST_APP_ID")
5 | password <- Sys.getenv("AZ_TEST_PASSWORD")
6 | subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
7 |
8 | if(tenant == "" || app == "" || password == "" || subscription == "")
9 | skip("Tests skipped: ARM credentials not set")
10 |
11 | rgname <- make_name(10)
12 | rg <- AzureRMR::az_rm$
13 | new(tenant=tenant, app=app, password=password)$
14 | get_subscription(subscription)$
15 | create_resource_group(rgname, location="australiaeast")
16 |
17 | echo <- getOption("azure_containers_tool_echo")
18 | options(azure_containers_tool_echo=FALSE)
19 |
20 | test_that("AKS works with availability set",
21 | {
22 | aksname <- make_name(10)
23 | expect_true(is_aks(rg$create_aks(aksname, agent_pools=agent_pool("pool1", 1, use_scaleset=FALSE),
24 | managed_identity=TRUE)))
25 |
26 | aks <- rg$get_aks(aksname)
27 | expect_true(is_aks(aks))
28 |
29 | pool1 <- aks$get_agent_pool("pool1")
30 | expect_is(pool1, "az_agent_pool")
31 |
32 | pools <- aks$list_agent_pools()
33 | expect_true(is.list(pools) && length(pools) == 1 && all(sapply(pools, inherits, "az_agent_pool")))
34 |
35 | expect_error(aks$create_agent_pool("pool2", 1, disksize=500, wait=TRUE))
36 |
37 | clus <- aks$get_cluster()
38 | expect_true(is_kubernetes_cluster(clus))
39 | })
40 |
41 |
42 | teardown({
43 | options(azure_containers_tool_echo=echo)
44 | suppressMessages(rg$delete(confirm=FALSE))
45 | })
46 |
--------------------------------------------------------------------------------
/tests/testthat/test03f_aks_private.R:
--------------------------------------------------------------------------------
1 | context("AKS interface with managed identity/private cluster")
2 |
3 | tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
4 | app <- Sys.getenv("AZ_TEST_APP_ID")
5 | password <- Sys.getenv("AZ_TEST_PASSWORD")
6 | subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
7 |
8 | if(tenant == "" || app == "" || password == "" || subscription == "")
9 | skip("Tests skipped: ARM credentials not set")
10 |
11 | rgname <- make_name(10)
12 | rg <- AzureRMR::az_rm$
13 | new(tenant=tenant, app=app, password=password)$
14 | get_subscription(subscription)$
15 | create_resource_group(rgname, location="australiaeast")
16 |
17 | echo <- getOption("azure_containers_tool_echo")
18 | options(azure_containers_tool_echo=FALSE)
19 |
20 | test_that("AKS works with private cluster",
21 | {
22 | aksname <- make_name(10)
23 | expect_true(is_aks(rg$create_aks(aksname, agent_pools=agent_pool("pool1", 1),
24 | managed_identity=TRUE, private_cluster=TRUE)))
25 | aks <- rg$get_aks(aksname)
26 | expect_true(is_aks(aks))
27 |
28 | # no SP password with svc identity
29 | expect_error(aks$update_service_password())
30 |
31 | pool1 <- aks$get_agent_pool("pool1")
32 | expect_is(pool1, "az_agent_pool")
33 |
34 | pools <- aks$list_agent_pools()
35 | expect_true(is.list(pools) && length(pools) == 1 && all(sapply(pools, inherits, "az_agent_pool")))
36 |
37 | clus <- aks$get_cluster()
38 | expect_true(is_kubernetes_cluster(clus))
39 | })
40 |
41 |
42 | teardown({
43 | options(azure_containers_tool_echo=echo)
44 | suppressMessages(rg$delete(confirm=FALSE))
45 | })
46 |
--------------------------------------------------------------------------------
/vignettes/perms2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudyr/AzureContainers/e1c3644eb2dd4e4167ad79d5816f1ef06a7011eb/vignettes/perms2.png
--------------------------------------------------------------------------------
/vignettes/vig01_plumber_deploy.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Deploying a prediction service with Plumber"
3 | Author: Hong Ooi
4 | output: rmarkdown::html_vignette
5 | vignette: >
6 | %\VignetteIndexEntry{Plumber model deployment}
7 | %\VignetteEngine{knitr::rmarkdown}
8 | %\VignetteEncoding{utf8}
9 | ---
10 |
11 | This document shows how you can deploy a fitted model as a web service using ACR, ACI and AKS. The framework used is [Plumber](https://www.rplumber.io), a package to expose your R code as a service via a REST API.
12 |
13 |
14 | ## Fit the model
15 |
16 | We'll fit a simple model for illustrative purposes, using the Boston housing dataset which ships with R (in the MASS package). To make the deployment process more interesting, the model we fit will be a random forest, using the randomForest package.
17 |
18 | ```r
19 | data(Boston, package="MASS")
20 | library(randomForest)
21 |
22 | # train a model for median house price as a function of the other variables
23 | bos_rf <- randomForest(medv ~ ., data=Boston, ntree=100)
24 |
25 | # save the model
26 | saveRDS(bos_rf, "bos_rf.rds")
27 | ```
28 |
29 | ## Scoring script for plumber
30 |
31 | Now that we have the model, we also need a script to obtain predicted values from it given a set of inputs:
32 |
33 | ```r
34 | # save as bos_rf_score.R
35 |
36 | bos_rf <- readRDS("bos_rf.rds")
37 | library(randomForest)
38 |
39 | #* @param df data frame of variables
40 | #* @post /score
41 | function(req, df)
42 | {
43 | df <- as.data.frame(df)
44 | predict(bos_rf, df)
45 | }
46 | ```
47 |
48 | This is fairly straightforward, but the comments may require some explanation. They are plumber annotations that tell it to call the function if the server receives a HTTP POST request with the path `/score`, and query parameter `df`. The value of the `df` parameter is then converted to a data frame, and passed to the randomForest `predict` method.
49 |
50 |
51 | ## Create a Dockerfile
52 |
53 | Let's package up the model and the scoring script into a Docker image. A Dockerfile to do this would look like the following. This uses the base image supplied by Plumber (`trestletech/plumber`), installs randomForest, and then adds the model and the above scoring script. Finally, it runs the code that will start the server and listen on port 8000.
54 |
55 | ```dockerfile
56 | # example Dockerfile to expose a plumber service
57 |
58 | FROM trestletech/plumber
59 |
60 | # install the randomForest package
61 | RUN R -e 'install.packages(c("randomForest"))'
62 |
63 | # copy model and scoring script
64 | RUN mkdir /data
65 | COPY bos_rf.rds /data
66 | COPY bos_rf_score.R /data
67 | WORKDIR /data
68 |
69 | # plumb and run server
70 | EXPOSE 8000
71 | ENTRYPOINT ["R", "-e", \
72 | "pr <- plumber::plumb('/data/bos_rf_score.R'); pr$run(host='0.0.0.0', port=8000)"]
73 | ```
74 |
75 | ## Build and upload the image
76 |
77 | The code to store our image on Azure Container Registry is as follows. If you are running this code, you should substitute the values of `tenant`, `app` and/or `secret` from your Azure service principal. Similarly, if you are using the public Azure cloud, note that all ACR instances share a common DNS namespace, as do all ACI and AKS instances.
78 |
79 | For more information on how to create a service principal, see the [AzureRMR readme](https://github.com/cloudyr/AzureRMR).
80 |
81 | ```r
82 | library(AzureContainers)
83 |
84 | # create a resource group for our deployments
85 | deployresgrp <- AzureRMR::get_azure_login()$
86 | get_subscription("sub_id")$
87 | create_resource_group("deployresgrp", location="australiaeast")
88 |
89 | # create container registry
90 | deployreg_svc <- deployresgrp$create_acr("deployreg")
91 |
92 | # build image 'bos_rf'
93 | call_docker("build -t bos_rf .")
94 |
95 | # upload the image to Azure
96 | deployreg <- deployreg_svc$get_docker_registry(as_admin=TRUE)
97 | deployreg$push("bos_rf")
98 | ```
99 |
100 | If you run this code, you should see a lot of output indicating that R is downloading, compiling and installing randomForest, and finally that the image is being pushed to Azure. (You will see this output even if your machine already has the randomForest package installed. This is because the package is being installed to the R session _inside the container_, which is distinct from the one running the code shown here.)
101 |
102 | All Docker calls in AzureContainers, like the one to build the image, return the actual docker commandline as the `cmdline` attribute of the (invisible) returned value. In this case, the commandline is `docker build -t bos_rf .` Similarly, the `push()` method actually involves two Docker calls, one to retag the image, and the second to do the actual pushing; the returned value in this case will be a 2-component list with the command lines being `docker tag bos_rf deployreg.azurecr.io/bos_rf` and `docker push deployreg.azurecr.io/bos_rf`.
103 |
104 |
105 | ## Deploy to an Azure Container Instance
106 |
107 | The simplest way to deploy a service is via a Container Instance. The following code creates a single running container which contains our model, listening on port 8000.
108 |
109 | ```r
110 | # create an instance with 2 cores and 8GB memory, and deploy our image
111 | deployaci <- deployresgrp$create_aci("deployaci",
112 | image="deployreg.azurecr.io/bos_rf",
113 | registry_creds=deployreg,
114 | cores=2, memory=8,
115 | ports=aci_ports(8000))
116 | ```
117 |
118 | Once the instance is running, let's call the prediction API with some sample data. By default, AzureContainers will assign the container a domain name with prefix taken from the instance name. The port is 8000 as specified in the Dockerfile, and the URI path is `/score` indicating we want to call the scoring function defined earlier.
119 |
120 | The data to be scored---the first 10 rows of the Boston dataset---is passed in the _body_ of the request as a named list, encoded as JSON. A feature of Plumber is that, when the body of the request is in this format, it will extract the elements of the list and pass them to the scoring function as named arguments. This makes it easy to pass around relatively large amounts of data, eg if the data is wide, or for scoring multiple rows at a time. For more information on how to create and interact with Plumber APIs, consult the [Plumber documentation](https://www.rplumber.io/docs/).
121 |
122 | ```r
123 | response <- httr::POST("http://deployaci.australiaeast.azurecontainer.io:8000/score",
124 | body=list(df=MASS::Boston[1:10,]), encode="json")
125 | httr::content(response, simplifyVector=TRUE)
126 | #> [1] 25.9269 22.0636 34.1876 33.7737 34.8081 27.6394 21.8007 22.3577 16.7812 18.9785
127 | ```
128 |
129 |
130 | ## Deploy to a Kubernetes cluster
131 |
132 | Deploying a service to a container instance is simple, but lacks many features that are important in a production setting. A better alternative for production purposes is to deploy to a Kubernetes cluster. Such a cluster can be created using Azure Kubernetes Service (AKS).
133 |
134 | ```r
135 | # create a Kubernetes cluster with 2 nodes, running Linux (the default)
136 | deployclus_svc <- deployresgrp$create_aks("deployclus", agent_pools=agent_pool("pool1", 2))
137 | ```
138 |
139 | Unlike an ACI resource, creating a Kubernetes cluster can take several minutes. By default, the `create_aks()` method will wait until the cluster provisioning is complete before it returns.
140 |
141 | Having created the cluster, we can deploy our model and create a service. We'll use a YAML configuration file to specify the details for the deployment and service API. The image to be deployed is the same as before.
142 |
143 | ```yaml
144 | apiVersion: apps/v1
145 | kind: Deployment
146 | metadata:
147 | name: bos-rf
148 | spec:
149 | selector:
150 | matchLabels:
151 | app: bos-rf
152 | replicas: 1
153 | template:
154 | metadata:
155 | labels:
156 | app: bos-rf
157 | spec:
158 | containers:
159 | - name: bos-rf
160 | image: deployreg.azurecr.io/bos_rf
161 | ports:
162 | - containerPort: 8000
163 | resources:
164 | requests:
165 | cpu: 250m
166 | limits:
167 | cpu: 500m
168 | imagePullSecrets:
169 | - name: deployreg.azurecr.io
170 | ---
171 | apiVersion: v1
172 | kind: Service
173 | metadata:
174 | name: bos-rf-svc
175 | spec:
176 | selector:
177 | app: bos-rf
178 | type: LoadBalancer
179 | ports:
180 | - protocol: TCP
181 | port: 8000
182 | ```
183 |
184 | The following code will obtain the cluster endpoint from the AKS resource and then deploy the image and service to the cluster. The configuration details for the `deployclus` cluster are stored in a file located in the R temporary directory; all of the cluster's methods will use this file. Unless told otherwise, AzureContainers does not touch your default Kubernetes configuration (`~/kube/config`).
185 |
186 | ```r
187 | # grant the cluster pull access to the registry
188 | deployreg_svc$add_role_assignment(deployclus_svc, "Acrpull")
189 |
190 | # get the cluster endpoint
191 | deployclus <- deployclus_svc$get_cluster()
192 |
193 | # create and start the service
194 | deployclus$create("bos_rf.yaml")
195 | ```
196 |
197 | To check on the progress of the deployment, run the `get()` methods specifying the type and name of the resource to get information on. As with Docker, these correspond to calls to the `kubectl` commandline tool, and again, the actual commandline is stored as the `cmdline` attribute of the returned value.
198 |
199 | ```r
200 | deployclus$get("deployment bos-rf")
201 | #> Kubernetes operation: get deployment bos-rf --kubeconfig=".../kubeconfigxxxx"
202 | #> NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
203 | #> bos-rf 1 1 1 1 5m
204 |
205 | svc <- read.table(text=deployclus$get("service bos-rf-svc")$stdout, header=TRUE)
206 | #> Kubernetes operation: get service bos-rf-svc --kubeconfig=".../kubeconfigxxxx"
207 | #> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
208 | #> bos-rf-svc LoadBalancer 10.0.8.189 52.187.249.58 8000:32276/TCP 5m
209 | ```
210 |
211 | Once the service is up and running, as indicated by the presence of an external IP in the service details, let's test it with a HTTP request. The response should be the same as it was with the container instance. Notice how we extract the IP address from the service details above.
212 |
213 | ```r
214 | response <- httr::POST(paste0("http://", svc$EXTERNAL.IP[1], ":8000/score"),
215 | body=list(df=MASS::Boston[1:10, ]), encode="json")
216 | httr::content(response, simplifyVector=TRUE)
217 | #> [1] 25.9269 22.0636 34.1876 33.7737 34.8081 27.6394 21.8007 22.3577 16.7812 18.9785
218 | ```
219 |
220 | Finally, once we are done, we can tear down the service and deployment. Depending on the version of Kubernetes the cluster is running, deleting the service may take a few minutes.
221 |
222 | ```r
223 | deployclus$delete("service", "bos-rf-svc")
224 | deployclus$delete("deployment", "bos-rf")
225 | ```
226 |
227 | And if required, we can also delete all the resources created here, by simply deleting the resource group (AzureContainers will prompt you for confirmation):
228 |
229 | ```r
230 | deployresgrp$delete()
231 | ```
232 |
233 | ### Security note
234 |
235 | One important thing to note about the above example is that it is **insecure**. The Plumber service is exposed over HTTP, and there is no authentication layer: anyone on the Internet can contact the service and interact with it. Therefore, it's highly recommended that you should provide at least some level of authentication, as well as restricting the service to HTTPS only (this will require deploying an ingress controller to the Kubernetes cluster). You can also create the AKS resource as a private cluster; however, be aware that if you do this, you can only interact with the cluster endpoint from a host which is on the cluster's own subnet.
236 |
237 |
238 | ## See also
239 |
240 | Plumber is a relatively simple framework for creating and deploying services. As an alternative, the [RestRserve](https://restrserve.org) package is a more comprehensive framework, built on top of functionality provided by Rserve. It includes features such as automatic parallelisation, support for HTTPS, and support for basic and bearer authentication schemes. See the vignette "Deploying an ACI service with HTTPS and authentication" for more information.
241 |
--------------------------------------------------------------------------------
/vignettes/vig02_restrserve_deploy_aci.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Deploying an ACI service with HTTPS and authentication"
3 | Author: Hong Ooi
4 | output: rmarkdown::html_vignette
5 | vignette: >
6 | %\VignetteIndexEntry{RestRserve model deployment to ACI}
7 | %\VignetteEngine{knitr::rmarkdown}
8 | %\VignetteEncoding{utf8}
9 | ---
10 |
11 | This document shows how you can deploy a fitted model as a web service to an Azure Container Instance, using the [RestRserve](https://restrserve.org) package. RestRserve has a number of features that can make it more suitable than Plumber for building robust, production-ready services. These include:
12 |
13 | - Automatic parallelisation, based on the Rserve backend
14 | - Support for HTTPS
15 | - Support for basic and bearer HTTP authentication schemes
16 |
17 | In particular, we'll show how to implement the latter two features in this vignette.
18 |
19 | ## Deployment artifacts
20 |
21 | ### Model object
22 |
23 | For illustrative purposes, we'll reuse the random forest model and resource group from the Plumber deployment vignette. The code to fit the model is reproduced below for convenience.
24 |
25 | ```r
26 | data(Boston, package="MASS")
27 | library(randomForest)
28 |
29 | # train a model for median house price as a function of the other variables
30 | bos_rf <- randomForest(medv ~ ., data=Boston, ntree=100)
31 |
32 | # save the model
33 | saveRDS(bos_rf, "bos_rf.rds")
34 | ```
35 |
36 | Basic authentication requires that we provide a list of usernames and passwords that grant access to the service. In a production setting, you would typically query a database, directory service or other backing store to authenticate users. To keep this example simple, we'll just create a flat file in the standard [Apache `.htpasswd` format](https://en.wikipedia.org/wiki/.htpasswd). In this format, the passwords are encrypted using a variety of algorithms, as a security measure; we'll use the bcrypt algorithm since an R implementation is available in the package of that name.
37 |
38 | ```r
39 | library(bcrypt)
40 |
41 | user_list <- list(
42 | c("user1", "password1"),
43 | c("user2", "password2")
44 | )
45 | user_str <- sapply(user_list, function(x) paste(x[1], hashpw(x[2]), sep=":"))
46 | writeLines(user_str, ".htpasswd")
47 | ```
48 |
49 | ### TLS certificate/private key
50 |
51 | To enable HTTPS, we need to provide a TLS certificate and private key. Again, in a production setting, the cert will typically be provided to you; for this vignette, we'll generate a self-signed cert instead. If you are running Linux or MacOS and have openssl installed, you can use that to generate the cert. Here, since we're already using Azure, we'll leverage the Azure Key Vault service to do it in a platform-independent manner.
52 |
53 | ```r
54 | library(AzureRMR)
55 | library(AzureContainers)
56 | library(AzureKeyVault)
57 |
58 | deployresgrp <- AzureRMR::get_azure_login()$
59 | get_subscription("sub_id")$
60 | get_resource_group("deployresgrp")
61 |
62 | # create the key vault
63 | vault_res <- deployresgrp$create_key_vault("mykeyvault")
64 |
65 | # get the vault endpoint
66 | kv <- vault_res$get_endpoint()
67 |
68 | # generate the certificate: use the DNS name of the ACI container endpoint
69 | kv$certificates$create(
70 | "deployrrsaci",
71 | "CN=deployrrsaci",
72 | x509=cert_x509_properties(dns_names=c("deployrrsaci.australiaeast.azurecontainer.io"))
73 | )
74 | secret <- kv$secrets$get("deployrrsaci")
75 | key <- sub("-----BEGIN CERTIFICATE-----.*$", "", secret$value)
76 | cer <- sub("^.*-----END PRIVATE KEY-----\n", "", secret$value)
77 | writeLines(key, "cert.key")
78 | writeLines(cer, "cert.cer")
79 | ```
80 |
81 | ### App
82 |
83 | Unlike Plumber, in RestRserve you define your service in R code, as a web app. An app is an object of R6 class `Application`: it contains various middleware and backend objects, and exposes the endpoint paths for your service. The overall server backend is of R6 class `BackendRserve`, and has responsibility for running and managing the app.
84 |
85 | The script below defines an app that exposes the scoring function on the `/score` path. Save this as `app.R`:
86 |
87 | ```r
88 | library(RestRserve)
89 | library(randomForest)
90 |
91 | bos_rf <- readRDS("bos_rf.rds")
92 |
93 | users <- local({
94 | usr <- read.table(".htpasswd", sep=":", stringsAsFactors=FALSE)
95 | structure(usr[[2]], names=usr[[1]])
96 | })
97 |
98 | # scoring function: calls predict() on the provided dataset
99 | # - input is a jsonified data frame, in the body of a POST request
100 | # - output is the predicted values
101 | score <- function(request, response)
102 | {
103 | df <- jsonlite::fromJSON(rawToChar(request$body), simplifyDataFrame=TRUE)
104 | sc <- predict(bos_rf, df)
105 |
106 | response$set_body(jsonlite::toJSON(sc, auto_unbox=TRUE))
107 | response$set_content_type("application/json")
108 | }
109 |
110 | # basic authentication against provided username/password values
111 | # use try() construct to ensure robustness against malicious input
112 | authenticate <- function(user, password)
113 | {
114 | res <- FALSE
115 | try({
116 | res <- bcrypt::checkpw(password, users[[user]])
117 | }, silent=TRUE)
118 | res
119 | }
120 |
121 | # chain of objects for app
122 | auth_backend <- AuthBackendBasic$new(FUN=authenticate)
123 | auth_mw <- AuthMiddleware$new(auth_backend=auth_backend, routes="/score")
124 | app <- Application$new(middleware=list(auth_mw))
125 | app$add_post(path="/score", FUN=score)
126 |
127 | backend <- BackendRserve$new(app)
128 | ```
129 |
130 | ### Dockerfile
131 |
132 | Here is the dockerfile for the image. Save this as `RestRserve-aci.dockerfile`:
133 |
134 | ```dockerfile
135 | FROM rexyai/restrserve
136 |
137 | # install required packages
138 | RUN Rscript -e "install.packages(c('randomForest', 'bcrypt'), repos='https://cloud.r-project.org')"
139 |
140 | # copy model object, cert files, user file and app script
141 | RUN mkdir /data
142 | COPY bos_rf.rds /data
143 | COPY .htpasswd /data
144 | COPY cert.cer /data
145 | COPY cert.key /data
146 | COPY app.R /data
147 |
148 | WORKDIR /data
149 |
150 | EXPOSE 8080
151 |
152 | CMD ["Rscript", "-e", "source('app.R'); backend$start(app, http_port=-1, https.port=8080, tls.key=normalizePath('cert.key'), tls.cert=normalizePath('cert.cer'))"]
153 | ```
154 |
155 | ## Create the container
156 |
157 | We now build the image and upload it to an Azure Container Registry. This assumes a fresh start; if you have created an ACR in this resource group already, you can reuse that instead by calling `get_acr` instead of `create_acr`.
158 |
159 | ```r
160 | call_docker("build -t rrs-aci -f RestRserve-aci.dockerfile .")
161 |
162 | deployreg_svc <- deployresgrp$create_acr("deployreg")
163 | deployreg <- deployreg_svc$get_docker_registry(as_admin=TRUE)
164 | deployreg$push("rrs-aci")
165 | ```
166 |
167 | We can now deploy the image to ACI and obtain predicted values from the RestRserve app. Because we used a self-signed certificate in this example, we need to turn off the SSL verification check that curl performs by default. There may also be a short delay from when the container is started, to when the app is ready to accept requests.
168 |
169 | ```r
170 | # ensure the name of the resource matches the one on the cert we obtained above
171 | deployresgrp$create_aci("deployrrsaci",
172 | image="deployreg.azurecr.io/bos-rrs-https",
173 | registry_creds=deployreg,
174 | cores=2, memory=8,
175 | ports=aci_ports(8080))
176 |
177 | Sys.sleep(30)
178 |
179 | # tell curl not to verify the cert
180 | unverified_handle <- function()
181 | {
182 | structure(list(
183 | handle=curl::handle_setopt(curl::new_handle(), ssl_verifypeer=FALSE),
184 | url="https://deployrrsaci.australiaeast.azurecontainer.io"),
185 | class="handle")
186 | }
187 |
188 | # send the username and password as part of the request
189 | response <- httr::POST("https://deployrrsaci.australiaeast.azurecontainer.io:8080/score",
190 | httr::authenticate("user1", "password1"),
191 | body=MASS::Boston[1:10, ], encode="json",
192 | handle=unverified_handle())
193 |
194 | httr::content(response, simplifyVector=TRUE)
195 | #> [1] 25.9269 22.0636 34.1876 33.7737 34.8081 27.6394 21.8007 22.3577 16.7812 18.9785
196 | ```
197 |
--------------------------------------------------------------------------------
/vignettes/vig03_securing_aks_traefik.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Securing an AKS deployment with Traefik"
3 | Author: Hong Ooi
4 | output: rmarkdown::html_vignette
5 | vignette: >
6 | %\VignetteIndexEntry{Securing an AKS deployment with Traefik}
7 | %\VignetteEngine{knitr::rmarkdown}
8 | %\VignetteEncoding{utf8}
9 | ---
10 |
11 | The vignette "Deploying a prediction service with Plumber" showed you how to deploy a simple prediction service to a Kubernetes cluster in Azure. That deployment had a number of drawbacks: chiefly, it was open to the public, and used HTTP and thus was vulnerable to man-in-the-middle (MITM) attacks. Here, we'll show how to address these issues with basic authentication and HTTPS. To run the code in this vignette, you'll need the helm binary installed on your machine in addition to docker and kubectl.
12 |
13 | ## Model object and image
14 |
15 | We'll reuse the image from the Plumber vignette. The code and artifacts to build this image are reproduced below for convenience.
16 |
17 | Save the model object:
18 |
19 | ```r
20 | data(Boston, package="MASS")
21 | library(randomForest)
22 |
23 | # train a model for median house price as a function of the other variables
24 | bos_rf <- randomForest(medv ~ ., data=Boston, ntree=100)
25 |
26 | # save the model
27 | saveRDS(bos_rf, "bos_rf.rds")
28 | ```
29 |
30 | Scoring script:
31 |
32 | ```r
33 | bos_rf <- readRDS("bos_rf.rds")
34 | library(randomForest)
35 |
36 | #* @param df data frame of variables
37 | #* @post /score
38 | function(req, df)
39 | {
40 | df <- as.data.frame(df)
41 | predict(bos_rf, df)
42 | }
43 | ```
44 |
45 | Dockerfile:
46 |
47 | ```dockerfile
48 | FROM trestletech/plumber
49 |
50 | # install the randomForest package
51 | RUN R -e 'install.packages(c("randomForest"))'
52 |
53 | # copy model and scoring script
54 | RUN mkdir /data
55 | COPY bos_rf.rds /data
56 | COPY bos_rf_score.R /data
57 | WORKDIR /data
58 |
59 | # plumb and run server
60 | EXPOSE 8000
61 | ENTRYPOINT ["R", "-e", \
62 | "pr <- plumber::plumb('/data/bos_rf_score.R'); pr$run(host='0.0.0.0', port=8000)"]
63 | ```
64 |
65 | Build and upload the image to ACR:
66 |
67 | ```r
68 | library(AzureContainers)
69 |
70 | # create a resource group for our deployments
71 | deployresgrp <- AzureRMR::get_azure_login()$
72 | get_subscription("sub_id")$
73 | create_resource_group("deployresgrp", location="australiaeast")
74 |
75 | # create container registry
76 | deployreg_svc <- deployresgrp$create_acr("deployreg")
77 |
78 | # build image 'bos_rf'
79 | call_docker("build -t bos_rf .")
80 |
81 | # upload the image to Azure
82 | deployreg <- deployreg_svc$get_docker_registry()
83 | deployreg$push("bos_rf")
84 | ```
85 |
86 | ## Deploy to AKS
87 |
88 | Create a new AKS resource for this deployment:
89 |
90 | ```r
91 | # create a Kubernetes cluster
92 | deployclus_svc <- deployresgrp$create_aks("secureclus", agent_pools=agent_pool("pool1", 2))
93 |
94 | # grant the cluster pull access to the registry
95 | deployreg_svc$add_role_assignment(deployclus_svc, "Acrpull")
96 | ```
97 |
98 | ### Install traefik
99 |
100 | The middleware we'll use to enable HTTPS and authentication is [Traefik](https://traefik.io/traefik/). This features built-in integration with Let's Encrypt, which is a popular source for TLS certificates (necessary for HTTPS). An alternative to Traefik is [Nginx](https://www.f5.com/go/product/welcome-to-nginx).
101 |
102 | Deploying traefik and enabling HTTPS involves the following steps, on top of deploying the model service itself:
103 |
104 | - Install traefik
105 | - Assign a domain name to the cluster's public IP address
106 | - Deploy the ingress route
107 |
108 | The following yaml contains the configuration parameters for traefik. Insert your email address where indicated (it will be used to obtain a certificate from Let's Encrypt), and save this as `traefik_values.yaml`.
109 |
110 | ```yaml
111 | # traefik_values.yaml
112 | fullnameOverride: traefik
113 | replicas: 1
114 | resources:
115 | limits:
116 | cpu: 500m
117 | memory: 500Mi
118 | requests:
119 | cpu: 100m
120 | memory: 200Mi
121 | externalTrafficPolicy: Local
122 | kubernetes:
123 | ingressClass: traefik
124 | ingressEndpoint:
125 | useDefaultPublishedService: true
126 | dashboard:
127 | enabled: false
128 | debug:
129 | enabled: false
130 | accessLogs:
131 | enabled: true
132 | fields:
133 | defaultMode: keep
134 | headers:
135 | defaultMode: keep
136 | names:
137 | Authorization: redact
138 | rbac:
139 | enabled: true
140 | acme:
141 | enabled: true
142 | email: "email.addr@example.com" # insert your email address here
143 | staging: false
144 | challengeType: tls-alpn-01
145 | ssl:
146 | enabled: true
147 | enforced: true
148 | permanentRedirect: true
149 | tlsMinVersion: VersionTLS12
150 | cipherSuites:
151 | - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
152 | - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
153 | - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
154 | - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
155 | - TLS_RSA_WITH_AES_128_GCM_SHA256
156 | - TLS_RSA_WITH_AES_256_GCM_SHA384
157 | - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
158 | ```
159 |
160 | We can now install traefik:
161 |
162 | ```r
163 | # get the cluster endpoint
164 | deployclus <- deployclus_svc$get_cluster()
165 |
166 | deployclus$helm("repo add stable https://kubernetes-charts.storage.googleapis.com/")
167 | deployclus$helm("repo update")
168 | deployclus$helm("install traefik-ingress stable/traefik --namespace kube-system --values traefik_values.yaml")
169 | ```
170 |
171 | ### Assign domain name
172 |
173 | Installing an ingress controller will create a public IP resource, which is the visible address for the cluster. It takes a minute or two for this resource to be created; once it appears, we assign a domain name to it.
174 |
175 | ```r
176 | for(i in 1:100)
177 | {
178 | res <- read.table(text=deployclus$get("service", "--all-namespaces")$stdout, header=TRUE, stringsAsFactors=FALSE)
179 | ip <- res$EXTERNAL.IP[res$NAME == "traefik"]
180 | if(ip != "")
181 | break
182 | Sys.sleep(10)
183 | }
184 | if(ip == "") stop("Ingress public IP not assigned")
185 |
186 | cluster_resources <- deployclus_svc$list_cluster_resources()
187 | found <- FALSE
188 | for(res in cluster_resources)
189 | {
190 | if(res$type != "Microsoft.Network/publicIPAddresses")
191 | next
192 | res$sync_fields()
193 | if(res$properties$ipAddress == ip)
194 | {
195 | found <- TRUE
196 | break
197 | }
198 | }
199 | if(!found) stop("Ingress public IP resource not found")
200 |
201 | # assign domain name to IP address
202 | res$do_operation(
203 | body=list(
204 | location=ip$location,
205 | properties=list(
206 | dnsSettings=list(domainNameLabel="secureclus"),
207 | publicIPAllocationMethod=ip$properties$publicIPAllocationMethod
208 | )
209 | ),
210 | http_verb="PUT"
211 | )
212 | ```
213 |
214 | ### Generate an auth file
215 |
216 | We'll use Traefik to handle authentication details. While some packages like RestRserve can also authenticate users, a key benefit of assigning this to the ingress controller is that it frees our container to focus purely on the task of returning predicted values. For example, if we want to switch to a different kind of model, we can do so without having to copy over any authentication code.
217 |
218 | Using basic auth with Traefik requires an authentication file, in [Apache `.htpasswd` format](https://en.wikipedia.org/wiki/.htpasswd). Here is R code to create such a file. This is essentially the same code that is used in the "Deploying an ACI service with HTTPS and authentication" vignette.
219 |
220 | ```r
221 | library(bcrypt)
222 |
223 | user_list <- list(
224 | c("user1", "password1")
225 | )
226 | user_str <- sapply(user_list, function(x) paste(x[1], hashpw(x[2]), sep=":"))
227 | writeLines(user_str, "auth")
228 | ```
229 |
230 | ### Deploy the service
231 |
232 | The yaml for the deployment and service is the same as in the original Plumber vignette. The main difference is that we now create a separate `bos-rf` namespace for our objects, which is the recommended practice: it allows us to manage the service independently of any others that may exist on the cluster.
233 |
234 | Save the following as `secure_deploy.yaml`:
235 |
236 | ```yaml
237 | # deployment.yaml
238 | apiVersion: apps/v1
239 | kind: Deployment
240 | metadata:
241 | name: bos-rf
242 | namespace: bos-rf
243 | spec:
244 | selector:
245 | matchLabels:
246 | app: bos-rf
247 | replicas: 1
248 | template:
249 | metadata:
250 | labels:
251 | app: bos-rf
252 | spec:
253 | containers:
254 | - name: bos-rf
255 | image: deployreg.azurecr.io/bos_rf # insert URI for your container registry/image
256 | ports:
257 | - containerPort: 8000
258 | resources:
259 | requests:
260 | cpu: 250m
261 | limits:
262 | cpu: 500m
263 | ---
264 | apiVersion: v1
265 | kind: Service
266 | metadata:
267 | name: bos-rf-svc
268 | namespace: bos-rf
269 | spec:
270 | selector:
271 | app: bos-rf
272 | ports:
273 | - protocol: TCP
274 | port: 8000
275 | ```
276 |
277 | The yaml to create the ingress route is below. Save this as `secure_ingress.yaml`.
278 |
279 | ```yaml
280 | # ingress.yaml
281 | apiVersion: extensions/v1beta1
282 | kind: Ingress
283 | metadata:
284 | name: bos-rf-ingress
285 | namespace: bos-rf
286 | annotations:
287 | kubernetes.io/ingress.class: traefik
288 | ingress.kubernetes.io/auth-type: basic
289 | ingress.kubernetes.io/auth-secret: bos-rf-secret
290 | spec:
291 | rules:
292 | - host: secureclus.australiaeast.cloudapp.azure.com
293 | http:
294 | paths:
295 | - path: /
296 | backend:
297 | serviceName: bos-rf-svc
298 | servicePort: 8000
299 | ```
300 |
301 | We can now create the deployment, service, and ingress route:
302 |
303 | ```r
304 | deployclus$kubectl("create namespace bos-rf")
305 | deployclus$kubectl("create secret generic bos-rf-secret --from-file=auth --namespace bos-rf")
306 | deployclus$create("secure_deploy.yaml")
307 | deployclus$apply("secure_ingress.yaml")
308 | ```
309 |
310 | ## Call the service
311 |
312 | Once the deployment is complete, we can obtain predicted values from it. Notice that we use the default HTTPS port for the request (port 443). While port 8000 is nominally exposed by the service, this is visible only within the cluster; it is connected to the external port 443 by Traefik.
313 |
314 | ```r
315 | response <- httr::POST("https://secureclus.australiaeast.cloudapp.azure.com/score",
316 | httr::authenticate("user1", "password1"),
317 | body=list(df=MASS::Boston[1:10,]), encode="json")
318 | httr::content(response, simplifyVector=TRUE)
319 | #> [1] 25.9269 22.0636 34.1876 33.7737 34.8081 27.6394 21.8007 22.3577 16.7812 18.9785
320 | ```
321 |
322 | ## Further comments
323 |
324 | In this vignette, we've secured the predictive service with a single username and password. While we could add more users to the authentication file, a more flexible and scalable solution is to use a frontend service, such as [Azure API Management](https://azure.microsoft.com/products/api-management/), or a directory service like [Microsoft Entra ID](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id) (previously known as Azure Active Directory). The specifics will typically be determined by your organisation's IT infrastructure, and are beyond the scope of this vignette.
325 |
326 |
--------------------------------------------------------------------------------
/vignettes/vig04_rbac.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "RBAC examples"
3 | Author: Hong Ooi
4 | output: rmarkdown::html_vignette
5 | vignette: >
6 | %\VignetteIndexEntry{RBAC examples}
7 | %\VignetteEngine{knitr::rmarkdown}
8 | %\VignetteEncoding{utf8}
9 | ---
10 |
11 | Working with role-based access control (RBAC) can be tricky, especially when containers are involved. This vignette provides example code snippets to handle some common use cases.
12 |
13 | ## Authenticating with a service principal from ACI to ACR
14 |
15 | This covers the scenario where you want to deploy an image to a container instance using a service principal, rather than the registry's admin credentials.
16 |
17 | ```r
18 | library(AzureGraph)
19 | az <- AzureRMR::get_azure_login()
20 | gr <- AzureGraph::get_graph_login()
21 |
22 | # create the registry
23 | rg <- az$
24 | get_subscription("sub_id")$
25 | get_resource_group("rgname")
26 |
27 | acr <- rg$create_acr("myacr")
28 |
29 | # create an app and give it pull access to the registry
30 | app <- gr$create_app("mycontainerapp")
31 | acr$add_role_assignment(app, "Acrpull")
32 |
33 | # build and push an image
34 | call_docker("build -t myimage .")
35 | reg <- acr$get_docker_registry()
36 | reg$push("myimage")
37 |
38 | # create an ACI credentials object containing the app ID and password
39 | creds <- aci_creds("myacr.azurecr.io", username=app$properties$appId, password=app$password)
40 |
41 | # create the instance, passing it the credentials object
42 | rg$create_aci("myinstance", image="myacr.azurecr.io/myimage",
43 | registry_creds=creds)
44 | ```
45 |
46 | ## Authenticating with a service principal from AKS to ACR
47 |
48 | The corresponding scenario for a Kubernetes cluster is much simpler: we simply call the `add_role_assignment` method for the ACR object, passing it the AKS object. We'll reuse the registry from the above example.
49 |
50 | ```r
51 | # create the AKS resource
52 | aks <- rg$create_aks("myaks", agent_pools=aks_pools("pool1", 2), enable_rbac=TRUE)
53 |
54 | # give the cluster pull access to the registry
55 | reg$add_role_assignment(aks, "Acrpull")
56 | ```
57 |
58 | After giving the cluster the necessary permissions, you can then deploy images from the registry as normal.
59 |
60 | ## Creating an AKS resource and reusing an existing service principal
61 |
62 | This scenario is most relevant when creating an AKS resource in an automated environment, ie without a logged-in user's credentials. Currently, creating an AKS resource also involves creating an associated service principal, for the cluster to manage its sub-resources. In turn, creating this service principal will attempt to get the credentials for the logged-in user, which fails if there is no user present.
63 |
64 | To avoid this, you can create an app ahead of time and pass it to `create_aks`:
65 |
66 | ```r
67 | # login to ARM and MS Graph with client credentials flow
68 | # your app must have the right permissions to work with ARM and Graph
69 | az <- AzureRMR::create_azure_login("mytenant", app="app_id", password="clientsecret")
70 | gr <- AzureGraph::create_graph_login("mytenant", app="app_id", password="clientsecret")
71 |
72 | app <- gr$create_app("myaksapp")
73 |
74 | az$get_subscription("sub_id")$
75 | get_resource_group("rgname")$
76 | create_aks("myaks",
77 | cluster_service_principal=app,
78 | agent_pools=aks_pools("pool1", 2, "Standard_DS2_v2", "Linux"))
79 | ```
80 |
81 | ## Integrating AKS with Azure Active Directory
82 |
83 | Integrating AKS and AAD requires creating two registered apps, the client and server, and giving them permissions to talk to each other. Most of the work here is actually done using the AzureGraph package; once the apps are correctly configured, we then pass them to the `create_aks` method. You'll need to be an administrator for your AAD tenant to carry out these steps.
84 |
85 | ```r
86 | # create the server app
87 | srvapp <- gr$create_app("akssrvapp")
88 |
89 | # save the app ID and password
90 | srvapp_id <- srvapp$properties$appId
91 | srvapp_pwd <- srvapp$password
92 |
93 | # update group membership claims
94 | srvapp$update(groupMembershipClaims="all")
95 |
96 | # update API permissions (Directory.Read.All scope & role, User.Read.All scope)
97 | srvapp$update(requiredResourceAccess=list(
98 | list(
99 | resourceAppId="00000003-0000-0000-c000-000000000000",
100 | resourceAccess=list(
101 | list(id="06da0dbc-49e2-44d2-8312-53f166ab848a", type="Scope"),
102 | list(id="e1fe6dd8-ba31-4d61-89e7-88639da4683d", type="Scope"),
103 | list(id="7ab1d382-f21e-4acd-a863-ba3e13f7da61", type="Role")
104 | )
105 | )
106 | ))
107 |
108 | # add OAuth permissions API
109 | srvapp_api <- srvapp$properties$api
110 | srvapp_newapi_id <- uuid::UUIDgenerate()
111 | srvapp_api$oauth2PermissionScopes <- list(
112 | list(
113 | adminConsentDescription="AKS",
114 | adminConsentDisplayName="AKS",
115 | id=srvapp_newapi_id,
116 | isEnabled=TRUE,
117 | type="User",
118 | userConsentDescription="AKS",
119 | userConsentDisplayName="AKS",
120 | value="AKS"
121 | )
122 | )
123 | srvapp$update(api=srvapp_api, identifierUris=I(sprintf("api://%s", srvapp_id)))
124 |
125 | # create the client app
126 | cliapp <- gr$create_app("akscliapp",
127 | isFallbackPublicClient=TRUE,
128 | publicClient=list(redirectUris=list("https://akscliapp"))
129 | )
130 | cliapp_id <- cliapp$properties$appId
131 |
132 | # tell the server app to trust the client
133 | srvapp_api <- srvapp$properties$api
134 | srvapp_api$preAuthorizedApplications <- list(
135 | list(
136 | appId=cliapp_id,
137 | permissionIds=list(srvapp_newapi_id)
138 | )
139 | )
140 | srvapp$update(api=srvapp_api)
141 | ```
142 |
143 | Once the apps have been configured, we still have to grant admin consent. This is best done in the Azure Portal:
144 |
145 | - Click on "Azure Active Directory" in the list of items on the left
146 | - In the AAD blade, click on "App registrations"
147 | - Find the app that you created, and click on it.
148 | - Click on "API permissions".
149 | - Click on the "Grant admin consent" button at the bottom of the pane.
150 |
151 | 
152 |
153 | Having created and configured the apps, we can then create the cluster resource.
154 |
155 | ```r
156 | rg$create_aks("akswithaad", agent_pools=aks_pools("pool1", 2),
157 | properties=list(
158 | aadProfile=list(
159 | clientAppID=cliapp_id,
160 | serverAppID=srvapp_id,
161 | serverAppSecret=srvapp_pwd
162 | )
163 | ),
164 | enable_rbac=TRUE
165 | )
166 | ```
167 |
168 | For more information, see the following Microsoft Docs pages:
169 |
170 | - [Enable Azure Active Directory integration](https://learn.microsoft.com/en-us/azure/aks/azure-ad-integration)
171 | - [Use Kubernetes RBAC with Azure AD integration](https://learn.microsoft.com/en-us/azure/aks/azure-ad-rbac)
172 |
--------------------------------------------------------------------------------