---
author: Simos Xenitellis
category: 容器与云
comments_data: []
count:
  commentnum: 0
  favtimes: 0
  likes: 0
  sharetimes: 0
  viewnum: 4021
date: '2018-02-24 21:25:37'
editorchoice: false
excerpt: 当你正在创建 LXD 容器的时候，你希望它们能被预先配置好。例如在容器一启动就自动执行 apt update来安装一些软件包，或者运行一些命令。
fromurl: https://blog.simos.info/how-to-preconfigure-lxd-containers-with-cloud-init/
id: 9381
islctt: true
largepic: /images/p/201802/24/212520cj6y0lj9jj49nvz4.jpg
permalink: /article-9381-1.html
pic: /images/p/201802/24/212520cj6y0lj9jj49nvz4.jpg.thumb.jpg
related: []
reviewer: ''
selector: ''
summary: 当你正在创建 LXD 容器的时候，你希望它们能被预先配置好。例如在容器一启动就自动执行 apt update来安装一些软件包，或者运行一些命令。
tags:
- LXD
- 容器
thumb: false
title: 如何使用 cloud-init 来预配置 LXD 容器
titlepic: true
translator: kaneg
updated: '2018-02-24 21:25:37'
---

![](/images/p/201802/24/212520cj6y0lj9jj49nvz4.jpg)


当你正在创建 LXD 容器的时候，你希望它们能被预先配置好。例如在容器一启动就自动执行 `apt update`来安装一些软件包，或者运行一些命令。


这篇文章将讲述如何用 [cloud-init](http://cloudinit.readthedocs.io/en/latest/index.html) 来对 [LXD 容器进行进行早期初始化](https://github.com/lxc/lxd/blob/master/doc/cloud-init.md)。


接下来，我们将创建一个包含cloud-init指令的LXD profile，然后启动一个新的容器来使用这个profile。


### 如何创建一个新的 LXD profile


查看已经存在的 profile：



```
$ lxc profile list
+---------|---------+
| NAME    | USED BY |
+---------|---------+
| default | 11      |
+---------|---------+

```

我们把名叫 `default` 的 profile 复制一份，然后在其内添加新的指令：



```
$ lxc profile copy default devprofile

$ lxc profile list
+------------|---------+
| NAME       | USED BY |
+------------|---------+
| default    | 11      |
+------------|---------+
| devprofile | 0       |
+------------|---------+

```

我们就得到了一个新的 profile： `devprofile`。下面是它的详情：



```
$ lxc profile show devprofile
config:
 environment.TZ: ""
description: Default LXD profile
devices:
 eth0:
 nictype: bridged
 parent: lxdbr0
 type: nic
 root:
 path: /
 pool: default
 type: disk
name: devprofile
used_by: []

```

注意这几个部分： `config:` 、 `description:` 、 `devices:` 、 `name:` 和 `used_by:`，当你修改这些内容的时候注意不要搞错缩进。（LCTT 译注：因为这些内容是 YAML 格式的，缩进是语法的一部分）


### 如何把 cloud-init 添加到 LXD profile 里


[cloud-init](http://cloudinit.readthedocs.io/en/latest/index.html) 可以添加到 LXD profile 的 `config` 里。当这些指令将被传递给容器后，会在容器第一次启动的时候执行。


下面是用在示例中的指令：



```
 package_upgrade: true
 packages:
 - build-essential
 locale: es_ES.UTF-8
 timezone: Europe/Madrid
 runcmd:
 - [touch, /tmp/simos_was_here]

```

`package_upgrade: true` 是指当容器第一次被启动时，我们想要 `cloud-init` 运行 `sudo apt upgrade`。`packages:` 列出了我们想要自动安装的软件。然后我们设置了 `locale` 和 `timezone`。在 Ubuntu 容器的镜像里，root 用户默认的 `locale` 是 `C.UTF-8`，而 `ubuntu` 用户则是 `en_US.UTF-8`。此外，我们把时区设置为 `Etc/UTC`。最后，我们展示了[如何使用 runcmd 来运行一个 Unix 命令](http://cloudinit.readthedocs.io/en/latest/topics/modules.html#runcmd)。


我们需要关注如何将 `cloud-init` 指令插入 LXD profile。


我首选的方法是：



```
$ lxc profile edit devprofile

```

它会打开一个文本编辑器，以便你将指令粘贴进去。[结果应该是这样的](https://paste.ubuntu.com/26313399/)：



```
$ lxc profile show devprofile
config:
  environment.TZ: ""
  user.user-data: |
    #cloud-config
    package_upgrade: true
    packages:
      - build-essential
    locale: es_ES.UTF-8
    timezone: Europe/Madrid
    runcmd:
      - [touch, /tmp/simos_was_here]
description: Default LXD profile
devices:
  eth0:
    nictype: bridged
    parent: lxdbr0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: devprofile
used_by: []

```

### 如何使用 LXD profile 启动一个容器


使用 profile `devprofile` 来启动一个新容器：



```
$ lxc launch --profile devprofile ubuntu:x mydev

```

然后访问该容器来查看我们的指令是否生效：



```
$ lxc exec mydev bash
root@mydev:~# ps ax
 PID TTY STAT TIME COMMAND
 1 ? Ss 0:00 /sbin/init
 ...
 427 ? Ss 0:00 /usr/bin/python3 /usr/bin/cloud-init modules --mode=f
 430 ? S 0:00 /bin/sh -c tee -a /var/log/cloud-init-output.log
 431 ? S 0:00 tee -a /var/log/cloud-init-output.log
 432 ? S 0:00 /usr/bin/apt-get --option=Dpkg::Options::=--force-con
 437 ? S 0:00 /usr/lib/apt/methods/http
 438 ? S 0:00 /usr/lib/apt/methods/http
 440 ? S 0:00 /usr/lib/apt/methods/gpgv
 570 ? Ss 0:00 bash
 624 ? S 0:00 /usr/lib/apt/methods/store
 625 ? R+ 0:00 ps ax
root@mydev:~#

```

如果我们连接得够快，通过 `ps ax` 将能够看到系统正在更新软件。我们可以从 `/var/log/cloud-init-output.log` 看到完整的日志：



```
Generating locales (this might take a while)...
 es_ES.UTF-8... done
Generation complete.

```

以上可以看出 `locale` 已经被更改了。root 用户还是保持默认的 `C.UTF-8`，只有非 root 用户 `ubuntu` 使用了新的`locale` 设置。



```
Hit:1 http://archive.ubuntu.com/ubuntu xenial InRelease
Get:2 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
Get:3 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]

```

以上是安装软件包之前执行的 `apt update`。



```
The following packages will be upgraded:
 libdrm2 libseccomp2 squashfs-tools unattended-upgrades
4 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 211 kB of archives.

```

以上是在执行 `package_upgrade: true` 和安装软件包。



```
The following NEW packages will be installed:
 binutils build-essential cpp cpp-5 dpkg-dev fakeroot g++ g++-5 gcc gcc-5
 libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl

```

以上是我们安装 `build-essential` 软件包的指令。


`runcmd` 执行的结果如何？



```
root@mydev:~# ls -l /tmp/
total 1
-rw-r--r-- 1 root root 0 Jan 3 15:23 simos_was_here
root@mydev:~#

```

可见它已经生效了！


### 结论


当我们启动 LXD 容器的时候，我们常常需要默认启用一些配置，并且希望能够避免重复工作。通常解决这个问题的方法是创建 LXD profile，然后把需要的配置添加进去。最后，当我们启动新的容器时，只需要应用该 LXD profile 即可。




---


via: <https://blog.simos.info/how-to-preconfigure-lxd-containers-with-cloud-init/>


作者：[Simos Xenitellis](https://blog.simos.info/author/simos/) 译者：[kaneg](https://github.com/kaneg) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出