mirror of
https://github.com/rancher/os.git
synced 2025-09-06 09:14:31 +00:00
Various fixes
This commit is contained in:
3
Dockerfile.docs
Normal file
3
Dockerfile.docs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
FROM squidfunk/mkdocs-material
|
||||||
|
RUN pip install mkdocs-markdownextradata-plugin
|
||||||
|
RUN apk add -U git openssh
|
62
README.md
62
README.md
@@ -1,62 +0,0 @@
|
|||||||
# RancherOS v2
|
|
||||||
|
|
||||||
# WORK IN PROGRESS
|
|
||||||
|
|
||||||
RancherOS v2 is an immutable Linux distribution built to run Rancher and
|
|
||||||
it's corresponding Kubernetes distributions [RKE2](https://rke2.io)
|
|
||||||
and [k3s](https://k3s.io). It is built using the [cOS-toolkit](https://rancher-sandbox.github.io/cos-toolkit-docs/docs/)
|
|
||||||
and based on openSUSE. Initial node configurations is done using only a
|
|
||||||
cloud-init style approach and all further maintenance is done using
|
|
||||||
Kubernetes operators.
|
|
||||||
|
|
||||||
## Use Cases
|
|
||||||
|
|
||||||
RancherOS is intended to be ran as the operating system beneath a Rancher Multi-Cluster
|
|
||||||
Management server or as a node in a Kubernetes cluster managed by Rancher. RancherOS
|
|
||||||
also allows you to build stand alone Kubernetes clusters that run an embedded
|
|
||||||
and smaller version of Rancher to manage the local cluster. A key attribute of RancherOS
|
|
||||||
is that it is managed by Rancher and thus Rancher will exist either locally in the cluster
|
|
||||||
or centrally with Rancher Multi-Cluster Manager.
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### OCI Image based
|
|
||||||
|
|
||||||
RancherOS v2 is an A/B style image based distribution. One first runs
|
|
||||||
on a read-only image A and to do an upgrade pulls a new read only image
|
|
||||||
B and then reboots the system to run on B. What is unique about
|
|
||||||
RancherOS v2 is that the runtime images come from OCI Images. Not an
|
|
||||||
OCI Image containing special artifacts, but an actual Docker runnable
|
|
||||||
image that is built using standard Docker build processes. RancherOS is
|
|
||||||
built using normal `docker build` and if you wish to customize the OS
|
|
||||||
image all you need to do is create a new `Dockerfile`.
|
|
||||||
|
|
||||||
### rancherd
|
|
||||||
|
|
||||||
RancherOS v2 includes no container runtime, Kubernetes distribution,
|
|
||||||
or Rancher itself. All of these assests are dynamically pulled at runtime. All that
|
|
||||||
is included in RancherOS is [rancherd](https://github.com/rancher/rancherd) which
|
|
||||||
is responsible for bootstrapping RKE2/k3s and Rancher from an OCI registry. This means
|
|
||||||
an update to containerd, k3s, RKE2, or Rancher does not require an OS upgrade
|
|
||||||
or node reboot.
|
|
||||||
|
|
||||||
### cloud-init
|
|
||||||
|
|
||||||
RancherOS v2 is initially configured using a simple version of `cloud-init`.
|
|
||||||
It is not expected that one will need to do a lot of customization to RancherOS
|
|
||||||
as the core OS's sole purpose is to run Rancher and Kubernetes and not serve as
|
|
||||||
a generic Linux distribution.
|
|
||||||
|
|
||||||
### RancherOS Operator
|
|
||||||
|
|
||||||
RancherOS v2 includes an operator that is responsible for managing OS upgrades
|
|
||||||
and assiting with secure device onboarding (SDO).
|
|
||||||
|
|
||||||
|
|
||||||
### openSUSE Leap
|
|
||||||
|
|
||||||
RancherOS v2 is based off of openSUSE Leap. There is no specific tie in to
|
|
||||||
openSUSE beyond that RancherOS assumes the underlying distribution is
|
|
||||||
based on systemd. We choose openSUSE for obvious reasons, but beyond
|
|
||||||
that openSUSE Leap provides a stable layer to build upon that is well
|
|
||||||
tested and has paths to commercial support, if one chooses.
|
|
@@ -3,6 +3,14 @@ kind: ClusterRole
|
|||||||
metadata:
|
metadata:
|
||||||
name: rancheros-operator
|
name: rancheros-operator
|
||||||
rules:
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- 'secrets'
|
||||||
|
verbs:
|
||||||
|
- 'get'
|
||||||
|
- 'watch'
|
||||||
|
- 'list'
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- rancheros.cattle.io
|
- rancheros.cattle.io
|
||||||
resources:
|
resources:
|
||||||
@@ -15,10 +23,19 @@ rules:
|
|||||||
- 'bundles'
|
- 'bundles'
|
||||||
verbs:
|
verbs:
|
||||||
- '*'
|
- '*'
|
||||||
|
- apiGroups:
|
||||||
|
- provisioning.cattle.io
|
||||||
|
resources:
|
||||||
|
- 'clusters'
|
||||||
|
verbs:
|
||||||
|
- 'get'
|
||||||
|
- 'watch'
|
||||||
|
- 'list'
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- management.cattle.io
|
- management.cattle.io
|
||||||
resources:
|
resources:
|
||||||
- 'settings'
|
- 'settings'
|
||||||
|
- 'clusterregistrationtokens'
|
||||||
verbs:
|
verbs:
|
||||||
- 'get'
|
- 'get'
|
||||||
- 'watch'
|
- 'watch'
|
||||||
|
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
output = flag.Bool("automatic", false, "Check for and run automatic installation")
|
automatic = flag.Bool("automatic", false, "Check for and run automatic installation")
|
||||||
printConfig = flag.Bool("print-config", false, "Print effective configuration and exit")
|
printConfig = flag.Bool("print-config", false, "Print effective configuration and exit")
|
||||||
configFile = flag.String("config-file", "", "Config file to use, local file or http/tftp URL")
|
configFile = flag.String("config-file", "", "Config file to use, local file or http/tftp URL")
|
||||||
)
|
)
|
||||||
@@ -31,7 +31,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := install.Run(*output, *configFile); err != nil {
|
if err := install.Run(*automatic, *configFile); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# This is required for booting a squashfs from network
|
# This is required for booting a squashfs from network
|
||||||
add_dracutmodules+=" livenet "
|
add_dracutmodules+=" livenet "
|
||||||
install_items+=" /etc/ssl "
|
install_items+=" /etc/ssl/* "
|
||||||
install_optional_items+=" /var/lib/ca-certificates "
|
install_optional_items+=" /var/lib/ca-certificates/* /var/lib/ca-certificates/*/* "
|
||||||
|
@@ -13,4 +13,4 @@ stages:
|
|||||||
entity: |
|
entity: |
|
||||||
kind: "shadow"
|
kind: "shadow"
|
||||||
username: "root"
|
username: "root"
|
||||||
password: "cos"
|
password: "ros"
|
||||||
|
@@ -12,8 +12,6 @@ metadata:
|
|||||||
namespace: fleet-local
|
namespace: fleet-local
|
||||||
spec:
|
spec:
|
||||||
osImage: "${IMAGE}"
|
osImage: "${IMAGE}"
|
||||||
clusterTargets:
|
|
||||||
- clusterName: local
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,7 +18,6 @@ type ManagedOSImage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ManagedOSImageSpec struct {
|
type ManagedOSImageSpec struct {
|
||||||
Paused bool `json:"paused,omitempty"`
|
|
||||||
OSImage string `json:"osImage,omitempty"`
|
OSImage string `json:"osImage,omitempty"`
|
||||||
NodeSelector *metav1.LabelSelector `json:"nodeSelector,omitempty"`
|
NodeSelector *metav1.LabelSelector `json:"nodeSelector,omitempty"`
|
||||||
Concurrency *int64 `json:"concurrency,omitempty"`
|
Concurrency *int64 `json:"concurrency,omitempty"`
|
||||||
|
@@ -15,7 +15,10 @@ type Install struct {
|
|||||||
NoFormat bool `json:"noFormat,omitempty"`
|
NoFormat bool `json:"noFormat,omitempty"`
|
||||||
Debug bool `json:"debug,omitempty"`
|
Debug bool `json:"debug,omitempty"`
|
||||||
TTY string `json:"tty,omitempty"`
|
TTY string `json:"tty,omitempty"`
|
||||||
Password string `json:"password,omitempy"`
|
ServerURL string `json:"-"`
|
||||||
|
Token string `json:"-"`
|
||||||
|
Role string `json:"-"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -25,12 +28,19 @@ type Config struct {
|
|||||||
|
|
||||||
type YipConfig struct {
|
type YipConfig struct {
|
||||||
Stages map[string][]Stage `json:"stages,omitempty"`
|
Stages map[string][]Stage `json:"stages,omitempty"`
|
||||||
|
Rancherd Rancherd `json:"rancherd,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Stage struct {
|
type Stage struct {
|
||||||
Users map[string]User `json:"users,omitempty"`
|
Users map[string]User `json:"users,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Rancherd struct {
|
||||||
|
Server string `json:"server,omitempty"`
|
||||||
|
Role string `json:"role,omitempty"`
|
||||||
|
Token string `json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
PasswordHash string `json:"passwd,omitempty"`
|
PasswordHash string `json:"passwd,omitempty"`
|
||||||
|
@@ -54,6 +54,35 @@ func mapToEnv(prefix string, data map[string]interface{}) []string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readFileFunc(path string) func() (map[string]interface{}, error) {
|
||||||
|
return func() (map[string]interface{}, error) {
|
||||||
|
return readFile(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readNested(data map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var (
|
||||||
|
nestedConfigFiles = convert.ToStringSlice(values.GetValueN(data, "rancheros", "install", "configUrl"))
|
||||||
|
funcs []reader
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(nestedConfigFiles) == 0 {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
values.RemoveValue(data, "rancheros", "install", "configUrl")
|
||||||
|
|
||||||
|
for _, nestedConfigFile := range nestedConfigFiles {
|
||||||
|
funcs = append(funcs, readFileFunc(nestedConfigFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
funcs = append(funcs, func() (map[string]interface{}, error) {
|
||||||
|
return data, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return merge(funcs...)
|
||||||
|
}
|
||||||
|
|
||||||
func readFile(path string) (result map[string]interface{}, _ error) {
|
func readFile(path string) (result map[string]interface{}, _ error) {
|
||||||
result = map[string]interface{}{}
|
result = map[string]interface{}{}
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -109,26 +138,17 @@ func merge(readers ...reader) (map[string]interface{}, error) {
|
|||||||
if err := schema.Mapper.ToInternal(newData); err != nil {
|
if err := schema.Mapper.ToInternal(newData); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
newData, err = readNested(newData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
d = values.MergeMapsConcatSlice(d, newData)
|
d = values.MergeMapsConcatSlice(d, newData)
|
||||||
}
|
}
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readConfigMap(cfg string) (map[string]interface{}, error) {
|
func readConfigMap(cfg string) (map[string]interface{}, error) {
|
||||||
var (
|
return merge(readCmdline, readFileFunc(cfg))
|
||||||
err error
|
|
||||||
data map[string]interface{}
|
|
||||||
)
|
|
||||||
return merge(func() (map[string]interface{}, error) {
|
|
||||||
data, err = merge(readCmdline,
|
|
||||||
func() (map[string]interface{}, error) {
|
|
||||||
return readFile(cfg)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return data, err
|
|
||||||
}, func() (map[string]interface{}, error) {
|
|
||||||
return readFile(convert.ToString(values.GetValueN(data, "rancheros", "install", "configUrl")))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadConfig(cfg string) (result Config, err error) {
|
func ReadConfig(cfg string) (result Config, err error) {
|
||||||
|
@@ -2,6 +2,7 @@ package managedos
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
|
"github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
|
||||||
provv1 "github.com/rancher/os2/pkg/apis/rancheros.cattle.io/v1"
|
provv1 "github.com/rancher/os2/pkg/apis/rancheros.cattle.io/v1"
|
||||||
@@ -71,6 +72,10 @@ func (h *handler) OnChange(mos *provv1.ManagedOSImage, status provv1.ManagedOSIm
|
|||||||
return nil, status, err
|
return nil, status, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mos.Namespace == "fleet-local" && len(mos.Spec.Targets) > 0 {
|
||||||
|
return nil, status, fmt.Errorf("spec.targets should be empty if in the fleet-local namespace")
|
||||||
|
}
|
||||||
|
|
||||||
bundle := &v1alpha1.Bundle{
|
bundle := &v1alpha1.Bundle{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name.SafeConcatName("mos", mos.Name),
|
Name: name.SafeConcatName("mos", mos.Name),
|
||||||
@@ -79,12 +84,15 @@ func (h *handler) OnChange(mos *provv1.ManagedOSImage, status provv1.ManagedOSIm
|
|||||||
Spec: v1alpha1.BundleSpec{
|
Spec: v1alpha1.BundleSpec{
|
||||||
Resources: resources,
|
Resources: resources,
|
||||||
BundleDeploymentOptions: v1alpha1.BundleDeploymentOptions{},
|
BundleDeploymentOptions: v1alpha1.BundleDeploymentOptions{},
|
||||||
Paused: mos.Spec.Paused,
|
|
||||||
RolloutStrategy: mos.Spec.ClusterRolloutStrategy,
|
RolloutStrategy: mos.Spec.ClusterRolloutStrategy,
|
||||||
Targets: mos.Spec.Targets,
|
Targets: mos.Spec.Targets,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mos.Namespace == "fleet-local" {
|
||||||
|
bundle.Spec.Targets = []v1alpha1.BundleTarget{{ClusterName: "local"}}
|
||||||
|
}
|
||||||
|
|
||||||
status, err = h.updateStatus(status, bundle)
|
status, err = h.updateStatus(status, bundle)
|
||||||
return []runtime.Object{
|
return []runtime.Object{
|
||||||
bundle,
|
bundle,
|
||||||
|
@@ -26,6 +26,10 @@ func Ask(cfg *config.Config) error {
|
|||||||
if err := AskPassword(cfg); err != nil {
|
if err := AskPassword(cfg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := AskServerAgent(cfg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -50,9 +54,33 @@ func AskInstallDevice(cfg *config.Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isServer(cfg *config.Config) (bool, bool, error) {
|
func AskToken(cfg *config.Config, server bool) error {
|
||||||
|
var (
|
||||||
|
token string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if cfg.RancherOS.Install.Token != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := "Token or cluster secret"
|
||||||
|
if server {
|
||||||
|
msg += " (optional)"
|
||||||
|
}
|
||||||
|
if server {
|
||||||
|
token, err = questions.PromptOptional(msg+": ", "")
|
||||||
|
} else {
|
||||||
|
token, err = questions.Prompt(msg+": ", "")
|
||||||
|
}
|
||||||
|
cfg.RancherOS.Install.Token = token
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func isServer() (bool, bool, error) {
|
||||||
opts := []string{"server", "agent", "none"}
|
opts := []string{"server", "agent", "none"}
|
||||||
i, err := questions.PromptFormattedOptions("Run as server or agent?", 0, opts...)
|
i, err := questions.PromptFormattedOptions("Run as server or agent (Choose none if building an image)?", 0, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, err
|
return false, false, err
|
||||||
}
|
}
|
||||||
@@ -60,6 +88,35 @@ func isServer(cfg *config.Config) (bool, bool, error) {
|
|||||||
return i == 0, i == 1, nil
|
return i == 0, i == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AskServerAgent(cfg *config.Config) error {
|
||||||
|
if cfg.RancherOS.Install.ServerURL != "" || cfg.RancherOS.Install.Silent {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
server, agent, err := isServer()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !server && !agent {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if server {
|
||||||
|
cfg.RancherOS.Install.Role = "server"
|
||||||
|
return AskToken(cfg, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.RancherOS.Install.Role = "agent"
|
||||||
|
url, err := questions.Prompt("URL of server: ", "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfg.RancherOS.Install.ServerURL = url
|
||||||
|
|
||||||
|
return AskToken(cfg, false)
|
||||||
|
}
|
||||||
|
|
||||||
func AskPassword(cfg *config.Config) error {
|
func AskPassword(cfg *config.Config) error {
|
||||||
if cfg.RancherOS.Install.Silent || cfg.RancherOS.Install.Password != "" {
|
if cfg.RancherOS.Install.Silent || cfg.RancherOS.Install.Password != "" {
|
||||||
return nil
|
return nil
|
||||||
|
@@ -55,7 +55,13 @@ func runInstall(cfg config.Config, output string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cfg.RancherOS.Install.ConfigURL == "" && !cfg.RancherOS.Install.Silent {
|
if cfg.RancherOS.Install.ConfigURL == "" && !cfg.RancherOS.Install.Silent {
|
||||||
yip := config.YipConfig{}
|
yip := config.YipConfig{
|
||||||
|
Rancherd: config.Rancherd{
|
||||||
|
Server: cfg.RancherOS.Install.ServerURL,
|
||||||
|
Token: cfg.RancherOS.Install.Token,
|
||||||
|
Role: cfg.RancherOS.Install.Role,
|
||||||
|
},
|
||||||
|
}
|
||||||
if cfg.RancherOS.Install.Password != "" || len(cfg.SSHAuthorizedKeys) > 0 {
|
if cfg.RancherOS.Install.Password != "" || len(cfg.SSHAuthorizedKeys) > 0 {
|
||||||
yip.Stages = map[string][]config.Stage{
|
yip.Stages = map[string][]config.Stage{
|
||||||
"network": {{
|
"network": {{
|
||||||
|
@@ -124,22 +124,31 @@ RUN cd /iso && \
|
|||||||
luet-makeiso iso.yaml
|
luet-makeiso iso.yaml
|
||||||
|
|
||||||
FROM iso-build AS qcow-build
|
FROM iso-build AS qcow-build
|
||||||
|
ARG ACCEL=tcg
|
||||||
RUN SUFFIX= && \
|
RUN SUFFIX= && \
|
||||||
FIRMWARE= && \
|
FIRMWARE= && \
|
||||||
if [ "$(uname -m)" = "aarch64" ]; then SUFFIX=-arm64; FIRMWARE=/usr/share/qemu/qemu-uefi-aarch64.bin; fi && \
|
if [ "$(uname -m)" = "aarch64" ]; then SUFFIX=-arm64; FIRMWARE=/usr/share/qemu/qemu-uefi-aarch64.bin; fi && \
|
||||||
PACKER_LOG=1 packer build \
|
echo '#!/bin/bash' > /usr/bin/image && \
|
||||||
|
echo 'set -e -x' >> /usr/bin/image && \
|
||||||
|
echo PACKER_LOG=1 packer build \
|
||||||
|
-var "root_password=ros" \
|
||||||
-var "firmware=${FIRMWARE}" \
|
-var "firmware=${FIRMWARE}" \
|
||||||
-var "memory=1024" \
|
-var "memory=1024" \
|
||||||
-var "iso=/iso/output.iso" \
|
-var "iso=/iso/output.iso" \
|
||||||
-var "accelerator=tcg" \
|
-var "accelerator=${ACCEL}" \
|
||||||
-only qemu.cos${SUFFIX} .
|
-only qemu.cos${SUFFIX} . >> /usr/bin/image && \
|
||||||
RUN mkdir /output && \
|
chmod +x /usr/bin/image
|
||||||
mv *.box /output/output.box && \
|
RUN echo 'mkdir /output &&' >> /usr/bin/image && \
|
||||||
pigz -dc *.tar.gz | tar xvf - && \
|
echo 'mv *.box /output/output.box' >> /usr/bin/image && \
|
||||||
cat cOS | pigz -c > /output/output.qcow.gz
|
echo 'pigz -dc *.tar.gz | tar xvf -' >> /usr/bin/image && \
|
||||||
|
echo 'cat cOS | pigz -c > /output/output.qcow.gz'>> /usr/bin/image
|
||||||
|
CMD ["bash", "-x", "/usr/bin/image"]
|
||||||
|
|
||||||
|
FROM qcow-build AS qcow-build2
|
||||||
|
RUN bash -x /usr/bin/image
|
||||||
|
|
||||||
FROM scratch AS qcow
|
FROM scratch AS qcow
|
||||||
COPY --from=qcow-build /output/ /
|
COPY --from=qcow-build2 /output/ /
|
||||||
|
|
||||||
FROM scratch AS iso
|
FROM scratch AS iso
|
||||||
COPY --from=iso-build /iso/output.iso /
|
COPY --from=iso-build /iso/output.iso /
|
||||||
@@ -153,12 +162,17 @@ ARG NAME=RancherOS-Image-dev
|
|||||||
ARG VERSION=1
|
ARG VERSION=1
|
||||||
ARG GIT_COMMIT=HEAD
|
ARG GIT_COMMIT=HEAD
|
||||||
RUN packer build \
|
RUN packer build \
|
||||||
|
-var "root_password=ros" \
|
||||||
-var "cos_version=${VERSION}" \
|
-var "cos_version=${VERSION}" \
|
||||||
-var "git_sha=${GIT_COMMIT}" \
|
-var "git_sha=${GIT_COMMIT}" \
|
||||||
-var 'aws_source_ami_filter_owners=["053594193760"]' \
|
-var 'aws_source_ami_filter_owners=["053594193760"]' \
|
||||||
-var "aws_cos_deploy_args=cos-deploy --no-verify --docker-image ${IMAGE}" \
|
-var "aws_cos_deploy_args=cos-deploy --no-verify --docker-image ${IMAGE}" \
|
||||||
-var "name=${NAME}" \
|
-var "name=${NAME}" \
|
||||||
-only amazon-ebs.cos .
|
-only amazon-ebs.cos .
|
||||||
|
|
||||||
|
FROM scratch AS default
|
||||||
|
COPY --from=iso / /
|
||||||
|
COPY --from=qcow / /
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +184,22 @@ iso()
|
|||||||
|
|
||||||
qcow()
|
qcow()
|
||||||
{
|
{
|
||||||
build --target qcow -o build/
|
ID=qcow-${RANDOM}
|
||||||
|
if docker run -it --device /dev/kvm busybox /bin/true; then
|
||||||
|
build --target qcow-build --build-arg ACCEL=kvm -t $ID
|
||||||
|
docker run --net=host -it --device /dev/kvm --name $ID $ID
|
||||||
|
else
|
||||||
|
build --target qcow-build --build-arg ACCEL=tcg -t $ID
|
||||||
|
docker run --net=host -it --name $ID $ID
|
||||||
|
fi || {
|
||||||
|
docker rm -fv $ID
|
||||||
|
docker rmi $ID
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
mkdir -p build/
|
||||||
|
docker export $ID | tar xvf - -C build/ output/ --strip-components=1
|
||||||
|
docker rm -fv $ID
|
||||||
|
docker rmi $ID
|
||||||
}
|
}
|
||||||
|
|
||||||
ami()
|
ami()
|
||||||
@@ -204,6 +233,11 @@ VERSION=${IMAGE##*:}
|
|||||||
NAME=${IMAGE%%:${VERSION}}
|
NAME=${IMAGE%%:${VERSION}}
|
||||||
NAME=${NAME//[^a-zA-Z0-9-@.\/_]/-}
|
NAME=${NAME//[^a-zA-Z0-9-@.\/_]/-}
|
||||||
|
|
||||||
|
if [ "$1" == dockerfile ]; then
|
||||||
|
dockerfile
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "${OUTPUT}" ] || [ -z "${IMAGE}" ] || echo "$@" | grep -q -- -h; then
|
if [ -z "${OUTPUT}" ] || [ -z "${IMAGE}" ] || echo "$@" | grep -q -- -h; then
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
@@ -222,10 +256,6 @@ fi
|
|||||||
iso)
|
iso)
|
||||||
iso
|
iso
|
||||||
;;
|
;;
|
||||||
dockerfile)
|
|
||||||
dockerfile
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
echo Unknown format $i
|
echo Unknown format $i
|
||||||
exit 1
|
exit 1
|
||||||
|
Reference in New Issue
Block a user