working with images
This commit is contained in:
parent
f464e8966d
commit
b021c161ca
@ -23,11 +23,23 @@ import (
|
|||||||
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||||
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||||
|
|
||||||
|
type InitScript struct {
|
||||||
|
Image string `json:"image"`
|
||||||
|
Command []string `json:"command"`
|
||||||
|
Args []string `json:"args"`
|
||||||
|
}
|
||||||
|
|
||||||
// ImageSpec defines the desired state of Image
|
// ImageSpec defines the desired state of Image
|
||||||
type ImageSpec struct {
|
type ImageSpec struct {
|
||||||
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
// Important: Run "make" to regenerate code after modifying this file
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
|
Name string `json:"name"`
|
||||||
Location string `json:"location"`
|
Location string `json:"location"`
|
||||||
|
WorkingDir string `json:"working_dir"`
|
||||||
|
Command []string `json:"command,omitempty"`
|
||||||
|
Ports []Port `json:"ports"`
|
||||||
|
Args []string `json:"args,omitempty"`
|
||||||
|
InitScript *InitScript `json:"init_script,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
@ -59,7 +59,7 @@ func (in *Image) DeepCopyInto(out *Image) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
out.Spec = in.Spec
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image.
|
||||||
@ -115,6 +115,26 @@ func (in *ImageList) DeepCopyObject() runtime.Object {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ImageSpec) DeepCopyInto(out *ImageSpec) {
|
func (in *ImageSpec) DeepCopyInto(out *ImageSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Command != nil {
|
||||||
|
in, out := &in.Command, &out.Command
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Ports != nil {
|
||||||
|
in, out := &in.Ports, &out.Ports
|
||||||
|
*out = make([]Port, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Args != nil {
|
||||||
|
in, out := &in.Args, &out.Args
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.InitScript != nil {
|
||||||
|
in, out := &in.InitScript, &out.InitScript
|
||||||
|
*out = new(InitScript)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageSpec.
|
||||||
@ -127,6 +147,31 @@ func (in *ImageSpec) DeepCopy() *ImageSpec {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *InitScript) DeepCopyInto(out *InitScript) {
|
||||||
|
*out = *in
|
||||||
|
if in.Command != nil {
|
||||||
|
in, out := &in.Command, &out.Command
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Args != nil {
|
||||||
|
in, out := &in.Args, &out.Args
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InitScript.
|
||||||
|
func (in *InitScript) DeepCopy() *InitScript {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(InitScript)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Port) DeepCopyInto(out *Port) {
|
func (in *Port) DeepCopyInto(out *Port) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -39,13 +39,57 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
description: ImageSpec defines the desired state of Image
|
description: ImageSpec defines the desired state of Image
|
||||||
properties:
|
properties:
|
||||||
|
args:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
command:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
init_script:
|
||||||
|
properties:
|
||||||
|
args:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
command:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
image:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- args
|
||||||
|
- command
|
||||||
|
- image
|
||||||
|
type: object
|
||||||
location:
|
location:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
Important: Run "make" to regenerate code after modifying this file
|
Important: Run "make" to regenerate code after modifying this file
|
||||||
type: string
|
type: string
|
||||||
|
ports:
|
||||||
|
items:
|
||||||
|
properties:
|
||||||
|
port:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
protocol:
|
||||||
|
description: Protocol defines network protocols supported for
|
||||||
|
things like container ports.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
working_dir:
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- location
|
- location
|
||||||
|
- name
|
||||||
|
- ports
|
||||||
|
- working_dir
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
served: true
|
served: true
|
||||||
|
@ -19,6 +19,7 @@ rules:
|
|||||||
- pods
|
- pods
|
||||||
verbs:
|
verbs:
|
||||||
- create
|
- create
|
||||||
|
- delete
|
||||||
- get
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
|
@ -4,6 +4,20 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/managed-by: kustomize
|
app.kubernetes.io/managed-by: kustomize
|
||||||
name: image-sample
|
name: minecraft-paper-1-21-4
|
||||||
spec:
|
spec:
|
||||||
# TODO(user): Add fields here
|
location: git.acooldomain.co/server-manager/minecraft:paper-1.21.4
|
||||||
|
name: minecraft:paper-1.21.4
|
||||||
|
working_dir: /opt/server
|
||||||
|
ports:
|
||||||
|
- port: 25565
|
||||||
|
protocol: TCP
|
||||||
|
|
||||||
|
init_script:
|
||||||
|
image: alpine:latest
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
args:
|
||||||
|
- /bin/sh
|
||||||
|
- "-c"
|
||||||
|
- "echo eula=true >> /data/eula.txt"
|
||||||
|
@ -11,8 +11,7 @@ spec:
|
|||||||
"on": true
|
"on": true
|
||||||
server:
|
server:
|
||||||
"on": true
|
"on": true
|
||||||
image: git.acooldomain.co/server-manager/minecraft:paper-1.21.4
|
image: minecraft-paper-1-21-4
|
||||||
working_dir: /opt/server
|
|
||||||
ports:
|
ports:
|
||||||
- protocol: TCP
|
- protocol: TCP
|
||||||
port: 25565
|
port: 25565
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
servermanagerv1alpha1 "git.acooldomain.co/server-manager/kubernetes-operator/api/v1alpha1"
|
servermanagerv1alpha1 "git.acooldomain.co/server-manager/kubernetes-operator/api/v1alpha1"
|
||||||
)
|
)
|
||||||
@ -95,7 +96,7 @@ type ServerManagerReconciler struct {
|
|||||||
// +kubebuilder:rbac:groups=,resources=persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=,resources=persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete
|
||||||
// +kubebuilder:rbac:groups=server-manager.acooldomain.co,resources=servermanagers/finalizers,verbs=update
|
// +kubebuilder:rbac:groups=server-manager.acooldomain.co,resources=servermanagers/finalizers,verbs=update
|
||||||
// +kubebuilder:rbac:groups=,resources=services,verbs=get;list;watch;create;update;patch;delete
|
// +kubebuilder:rbac:groups=,resources=services,verbs=get;list;watch;create;update;patch;delete
|
||||||
// +kubebuilder:rbac:groups=,resources=pods,verbs=get;list;watch;create
|
// +kubebuilder:rbac:groups=,resources=pods,verbs=get;list;watch;create;delete
|
||||||
|
|
||||||
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
// move the current state of the cluster closer to the desired state.
|
// move the current state of the cluster closer to the desired state.
|
||||||
@ -151,7 +152,13 @@ func (r *ServerManagerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
|||||||
}
|
}
|
||||||
logging.Info("verified browserPvc")
|
logging.Info("verified browserPvc")
|
||||||
|
|
||||||
serverPod := r.ServerPod(s, pvc)
|
image, err := r.GetImage(ctx, s)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error(err, "Failed to get image")
|
||||||
|
return reconcile.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
serverPod := r.ServerPod(s, pvc, image)
|
||||||
found := &corev1.Pod{}
|
found := &corev1.Pod{}
|
||||||
err = r.Get(ctx, client.ObjectKey{Namespace: pvc.Namespace, Name: pvc.Name}, found)
|
err = r.Get(ctx, client.ObjectKey{Namespace: pvc.Namespace, Name: pvc.Name}, found)
|
||||||
if err == nil && !s.Spec.Server.On {
|
if err == nil && !s.Spec.Server.On {
|
||||||
@ -602,8 +609,13 @@ func (r *ServerManagerReconciler) ServerPvc(s *servermanagerv1alpha1.ServerManag
|
|||||||
return pvc
|
return pvc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManager, pvc *corev1.PersistentVolumeClaim) *corev1.Pod {
|
func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManager, pvc *corev1.PersistentVolumeClaim, image *servermanagerv1alpha1.Image) *corev1.Pod {
|
||||||
ports := make([]corev1.ContainerPort, len(s.Spec.Server.Ports))
|
serverPorts := image.Spec.Ports
|
||||||
|
if len(s.Spec.Server.Ports) > 0 {
|
||||||
|
serverPorts = s.Spec.Server.Ports
|
||||||
|
}
|
||||||
|
|
||||||
|
ports := make([]corev1.ContainerPort, len(serverPorts))
|
||||||
|
|
||||||
for i, port := range s.Spec.Server.Ports {
|
for i, port := range s.Spec.Server.Ports {
|
||||||
ports[i] = corev1.ContainerPort{
|
ports[i] = corev1.ContainerPort{
|
||||||
@ -612,6 +624,36 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
command := image.Spec.Command
|
||||||
|
if len(s.Spec.Server.Command) > 0 {
|
||||||
|
command = s.Spec.Server.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
args := image.Spec.Args
|
||||||
|
if len(s.Spec.Server.Args) > 0 {
|
||||||
|
args = s.Spec.Server.Args
|
||||||
|
}
|
||||||
|
|
||||||
|
var initContainers []corev1.Container = nil
|
||||||
|
|
||||||
|
if image.Spec.InitScript != nil {
|
||||||
|
initContainers = []corev1.Container{
|
||||||
|
{
|
||||||
|
Name: "init",
|
||||||
|
Image: image.Spec.InitScript.Image,
|
||||||
|
ImagePullPolicy: corev1.PullIfNotPresent,
|
||||||
|
Command: image.Spec.Command,
|
||||||
|
Args: image.Spec.InitScript.Args,
|
||||||
|
VolumeMounts: []corev1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "volume",
|
||||||
|
MountPath: "/data",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pod := &corev1.Pod{
|
pod := &corev1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: s.Name,
|
Name: s.Name,
|
||||||
@ -629,18 +671,19 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
InitContainers: initContainers,
|
||||||
Containers: []corev1.Container{
|
Containers: []corev1.Container{
|
||||||
{
|
{
|
||||||
Name: "server",
|
Name: "server",
|
||||||
Image: s.Spec.Server.Image,
|
Image: image.Spec.Location,
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
ImagePullPolicy: corev1.PullAlways,
|
||||||
Command: s.Spec.Server.Command,
|
Command: command,
|
||||||
Args: s.Spec.Server.Args,
|
Args: args,
|
||||||
WorkingDir: s.Spec.Server.WorkingDir,
|
WorkingDir: image.Spec.WorkingDir,
|
||||||
Ports: ports,
|
Ports: ports,
|
||||||
VolumeMounts: []corev1.VolumeMount{{
|
VolumeMounts: []corev1.VolumeMount{{
|
||||||
Name: "volume",
|
Name: "volume",
|
||||||
MountPath: s.Spec.Server.WorkingDir,
|
MountPath: image.Spec.WorkingDir,
|
||||||
}},
|
}},
|
||||||
Stdin: true,
|
Stdin: true,
|
||||||
TTY: true,
|
TTY: true,
|
||||||
@ -648,10 +691,21 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
controllerutil.SetControllerReference(s, pod, r.Scheme)
|
controllerutil.SetControllerReference(s, pod, r.Scheme)
|
||||||
return pod
|
return pod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ServerManagerReconciler) GetImage(ctx context.Context, s *servermanagerv1alpha1.ServerManager) (*servermanagerv1alpha1.Image, error) {
|
||||||
|
image := &servermanagerv1alpha1.Image{}
|
||||||
|
err := r.Get(ctx, client.ObjectKey{Name: s.Spec.Server.Image, Namespace: s.Namespace}, image)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return image, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetupWithManager sets up the controller with the Manager.
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
func (r *ServerManagerReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
func (r *ServerManagerReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
Loading…
x
Reference in New Issue
Block a user