Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
09e9b5dabd | |||
95a1042c41 | |||
061f8d6d07 | |||
3a85e44ad4 | |||
4ebb402015 | |||
a54c905cc7 | |||
8f005effa3 | |||
7776d546e9 | |||
7ef824830e | |||
39f1c0d92c |
267
README.md
267
README.md
@@ -1,100 +1,240 @@
|
||||
# kubernetes-operator
|
||||
// TODO(user): Add simple overview of use/purpose
|
||||
# ServerManager Kubernetes Operator
|
||||
|
||||
A kubernetes operator used to manage servers using CRDs
|
||||
|
||||
## Description
|
||||
// TODO(user): An in-depth paragraph about your project and overview of use
|
||||
|
||||
## Getting Started
|
||||
This is a kubernetes operator used to manage game servers and is used in the implementation of the kubernetes instance manager in the [ServerManager backend](https://git.acooldomain.co/server-manager/backend)
|
||||
|
||||
### Prerequisites
|
||||
- go version v1.22.0+
|
||||
- docker version 17.03+.
|
||||
- kubectl version v1.11.3+.
|
||||
- Access to a Kubernetes v1.11.3+ cluster.
|
||||
## Important
|
||||
|
||||
### To Deploy on the cluster
|
||||
**Build and push your image to the location specified by `IMG`:**
|
||||
Currently the only supported ingress is traefik using the `IngressRoute` CRD
|
||||
|
||||
## Adding ServerManager operator to your cluster
|
||||
|
||||
### Install the CRDs
|
||||
|
||||
To install the CRDs you must first clone this repository using:
|
||||
|
||||
```sh
|
||||
make docker-build docker-push IMG=<some-registry>/kubernetes-operator:tag
|
||||
git clone https://git.acooldomain.co/server-manager/kubernetes-operator servermanager-operator
|
||||
cd servermanager-operator
|
||||
```
|
||||
|
||||
**NOTE:** This image ought to be published in the personal registry you specified.
|
||||
And it is required to have access to pull the image from the working environment.
|
||||
Make sure you have the proper permission to the registry if the above commands don’t work.
|
||||
|
||||
**Install the CRDs into the cluster:**
|
||||
After the repository is cloned to install the CRDs just apply them using:
|
||||
|
||||
```sh
|
||||
make install
|
||||
kubectl -f config/crd
|
||||
```
|
||||
|
||||
**Deploy the Manager to the cluster with the image specified by `IMG`:**
|
||||
### Setting up the ServerManager Operator
|
||||
|
||||
#### Configuration
|
||||
|
||||
The server-manager operator takes a configuration file called config.yaml and expects to find it in the same namespace under the name `server-manager-config` with a key named `config.yaml` containing a yaml file in the following schema
|
||||
|
||||
```yaml
|
||||
domain_label: string
|
||||
default_domain: string
|
||||
browser:
|
||||
domain: string
|
||||
sub_path: string
|
||||
auth_header: string
|
||||
cert_resolver: string
|
||||
entrypoints:
|
||||
- string
|
||||
|
||||
additional_routes:
|
||||
- IngressRouteRoute
|
||||
|
||||
middleware:
|
||||
name: string
|
||||
namespace: string
|
||||
```
|
||||
|
||||
#### Configuration values
|
||||
|
||||
> **domain_label**
|
||||
> optional
|
||||
> type: string
|
||||
> description: The name of a label on the node that it's value is a DNS record that points to that node.
|
||||
|
||||
> **default_domain**
|
||||
> type: string
|
||||
> description: The domain to use if the label in `domain_label` is not present on the node the pod runs on
|
||||
|
||||
> **browser.domain**
|
||||
> type: string
|
||||
> description: The domain that all file browsers would run on
|
||||
|
||||
> **browser.sub_path**
|
||||
> type: string
|
||||
> description: A path prefix that all browsers will run under
|
||||
|
||||
> **browser.auth_header**
|
||||
> type: string
|
||||
> description: The header used to identify a user on the browser container
|
||||
|
||||
> **browser.additional_routes**
|
||||
> type: IngressRouteRoute
|
||||
> description: Any additional routes that would point to anything other than the browser, usually needed for some forwardAuth middlewares
|
||||
|
||||
> **browser.middleware**
|
||||
> type: MiddlewareRef
|
||||
> description: A reference to the middleware that will handle authentication for the browsers
|
||||
|
||||
#### Example configuration
|
||||
|
||||
An example configuration that is close to what is used in [ServerManager](https://games.acooldomain.co)
|
||||
|
||||
```yaml
|
||||
domain_label: "ddns.acooldomain.co/hostname"
|
||||
default_domain: "acooldomain.co"
|
||||
browser:
|
||||
domain: games.acooldomain.co
|
||||
sub_path: /browsers
|
||||
auth_header: x-authentik-username
|
||||
cert_resolver: letsencrypt
|
||||
entrypoints:
|
||||
- websecure
|
||||
|
||||
additional_routes: # This additional route is required for the Authentik middleware
|
||||
- kind: Rule
|
||||
match: "Host(`games.acooldomain.co`) && PathPrefix(`/outpost.goauthentik.io/`)"
|
||||
priority: 15
|
||||
services:
|
||||
- kind: Service
|
||||
name: ak-outpost-traefik
|
||||
namespace: authentik
|
||||
port: 9000
|
||||
|
||||
middleware:
|
||||
name: authentik
|
||||
namespace: authentik
|
||||
```
|
||||
|
||||
And in a `ConfigMap` it looks as follows (replace `<namespace>` with the desired namespace):
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: server-manager-config
|
||||
namespace: <namespace>
|
||||
data:
|
||||
config.yaml: |
|
||||
domain_label: "ddns.acooldomain.co/hostname"
|
||||
default_domain: "acooldomain.co"
|
||||
browser:
|
||||
domain: games.acooldomain.co
|
||||
sub_path: /browsers
|
||||
auth_header: x-authentik-username
|
||||
cert_resolver: letsencrypt
|
||||
entrypoints:
|
||||
- websecure
|
||||
|
||||
additional_routes:
|
||||
- kind: Rule
|
||||
match: "Host(`games.acooldomain.co`) && PathPrefix(`/outpost.goauthentik.io/`)"
|
||||
priority: 15
|
||||
services:
|
||||
- kind: Service
|
||||
name: ak-outpost-traefik
|
||||
namespace: authentik
|
||||
port: 9000
|
||||
|
||||
middleware:
|
||||
name: authentik
|
||||
namespace: authentik
|
||||
|
||||
```
|
||||
|
||||
### Roles
|
||||
|
||||
The servermanager-operator requires permissions to **modify/create/delete** `pods`, `pvcs`, `services`, and `ingressroutes.traefik.io` to allow full functionality
|
||||
to create a service account with these permissions run the following commands where `<namespace>` is the namespace the operator would be deployed to
|
||||
|
||||
```sh
|
||||
make deploy IMG=<some-registry>/kubernetes-operator:tag
|
||||
kubectl apply -n <namespace> -f https://git.acooldomain.co/server-manager/kubernetes-operator/raw/branch/main/config/rbac/service-account.yaml
|
||||
kubectl apply -n <namespace> -f https://git.acooldomain.co/server-manager/kubernetes-operator/raw/branch/main/config/rbac/role.yaml
|
||||
kubectl apply -n <namespace> -f https://git.acooldomain.co/server-manager/kubernetes-operator/raw/branch/main/config/rbac/role-binding.yaml
|
||||
```
|
||||
|
||||
> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin
|
||||
privileges or be logged in as admin.
|
||||
### Manager
|
||||
|
||||
**Create instances of your solution**
|
||||
You can apply the samples (examples) from the config/sample:
|
||||
To install the operator itself after all the setup is complete simply run:
|
||||
|
||||
```sh
|
||||
kubectl apply -k config/samples/
|
||||
kubectl apply -n <namespace> -f https://git.acooldomain.co/server-manager/kubernetes-operator/raw/branch/main/config/manager/manager.yaml
|
||||
```
|
||||
|
||||
>**NOTE**: Ensure that the samples has default values to test it out.
|
||||
### Verify
|
||||
|
||||
### To Uninstall
|
||||
**Delete the instances (CRs) from the cluster:**
|
||||
After all the setup is applied you can test that the kubernetes-operator is working by creating a game image and a server that uses it.
|
||||
Below are exxamples for an Image that runs a minecraft paper server on version 1.21.5 and a Server using that image.
|
||||
|
||||
```sh
|
||||
kubectl delete -k config/samples/
|
||||
#### Example Image
|
||||
|
||||
```yaml
|
||||
apiVersion: server-manager.acooldomain.co/v1alpha1
|
||||
kind: Image
|
||||
metadata:
|
||||
name: minecraft-paper-1-21-5
|
||||
spec:
|
||||
location: git.acooldomain.co/server-manager/minecraft:paper-1.21.5
|
||||
name: minecraft
|
||||
tag: paper-1.21.5
|
||||
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"
|
||||
```
|
||||
|
||||
**Delete the APIs(CRDs) from the cluster:**
|
||||
#### Example Server
|
||||
|
||||
```sh
|
||||
make uninstall
|
||||
```yaml
|
||||
apiVersion: server-manager.acooldomain.co/v1alpha1
|
||||
kind: ServerManager
|
||||
metadata:
|
||||
name: test-server
|
||||
spec:
|
||||
storage: 10Gi
|
||||
browser:
|
||||
"on": true
|
||||
server:
|
||||
"on": true
|
||||
image: minecraft-paper-1-21-5
|
||||
ports:
|
||||
```
|
||||
|
||||
**UnDeploy the controller from the cluster:**
|
||||
#### Examples result
|
||||
|
||||
```sh
|
||||
make undeploy
|
||||
```
|
||||
After applying the following resources your environment should have several new resources created
|
||||
|
||||
## Project Distribution
|
||||
* PVCs
|
||||
* test-server
|
||||
* test-server-browser
|
||||
|
||||
Following are the steps to build the installer and distribute this project to users.
|
||||
* services
|
||||
* test-server
|
||||
* type: NodePort
|
||||
* ContainerPort: 25565
|
||||
* NodePort: Random Port
|
||||
|
||||
1. Build the installer for the image built and published in the registry:
|
||||
* Pods
|
||||
* test-server
|
||||
* test-server-browser
|
||||
|
||||
```sh
|
||||
make build-installer IMG=<some-registry>/kubernetes-operator:tag
|
||||
```
|
||||
|
||||
NOTE: The makefile target mentioned above generates an 'install.yaml'
|
||||
file in the dist directory. This file contains all the resources built
|
||||
with Kustomize, which are necessary to install this project without
|
||||
its dependencies.
|
||||
|
||||
2. Using the installer
|
||||
|
||||
Users can just run kubectl apply -f <URL for YAML BUNDLE> to install the project, i.e.:
|
||||
|
||||
```sh
|
||||
kubectl apply -f https://raw.githubusercontent.com/<org>/kubernetes-operator/<tag or branch>/dist/install.yaml
|
||||
```
|
||||
|
||||
## Contributing
|
||||
// TODO(user): Add detailed information on how you would like others to contribute to this project
|
||||
|
||||
**NOTE:** Run `make help` for more information on all potential `make` targets
|
||||
|
||||
More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)
|
||||
To delete the server and the related resources it is enough to delete the `server-manager.acooldomain.co` resource we created
|
||||
|
||||
## License
|
||||
|
||||
@@ -111,4 +251,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
@@ -37,6 +37,7 @@ type ImageSpec struct {
|
||||
Tag string `json:"tag"`
|
||||
Location string `json:"location"`
|
||||
WorkingDir string `json:"working_dir"`
|
||||
Volume string `json:"volume,omitempty"`
|
||||
Command []string `json:"command,omitempty"`
|
||||
Ports []Port `json:"ports"`
|
||||
Args []string `json:"args,omitempty"`
|
||||
|
@@ -44,6 +44,8 @@ type ServerStatus struct {
|
||||
Domain string `json:"domain,omitempty"`
|
||||
Running bool `json:"running,omitempty"`
|
||||
HostPorts []PortMapping `json:"host_ports,omitempty"`
|
||||
Args []string `json:"args,omitempty"`
|
||||
Command []string `json:"command,omitempty"`
|
||||
}
|
||||
|
||||
type ServerSpec struct {
|
||||
|
@@ -333,6 +333,16 @@ func (in *ServerStatus) DeepCopyInto(out *ServerStatus) {
|
||||
*out = make([]PortMapping, 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.Command != nil {
|
||||
in, out := &in.Command, &out.Command
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerStatus.
|
||||
|
@@ -146,8 +146,13 @@ func main() {
|
||||
setupLog.Error(err, "unable to start manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
configPath := os.Getenv("CONFIG_PATH")
|
||||
if configPath == "" {
|
||||
configPath = "config.yaml"
|
||||
}
|
||||
|
||||
config := &controller.ServerManagerReconcilerConfig{}
|
||||
configData, err := os.ReadFile("config.yaml")
|
||||
configData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to read config file")
|
||||
}
|
||||
|
23
config.yaml
23
config.yaml
@@ -1,23 +0,0 @@
|
||||
domain_label: "ddns.acooldomain.co/hostname"
|
||||
default_domain: "acooldomain.co"
|
||||
browser:
|
||||
domain: games.acooldomain.co
|
||||
sub_path: /browsers
|
||||
auth_header: x-authentik-username
|
||||
cert_resolver: letsencrypt
|
||||
entrypoints:
|
||||
- websecure
|
||||
|
||||
additional_routes:
|
||||
- kind: Rule
|
||||
match: "Host(`games.acooldomain.co`) && PathPrefix(`/outpost.goauthentik.io/`)"
|
||||
priority: 15
|
||||
services:
|
||||
- kind: Service
|
||||
name: ak-outpost-traefik
|
||||
namespace: authentik
|
||||
port: 9000
|
||||
|
||||
middleware:
|
||||
name: authentik
|
||||
namespace: authentik
|
@@ -85,6 +85,8 @@ spec:
|
||||
type: array
|
||||
tag:
|
||||
type: string
|
||||
volume:
|
||||
type: string
|
||||
working_dir:
|
||||
type: string
|
||||
required:
|
||||
|
@@ -94,6 +94,14 @@ spec:
|
||||
INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||
Important: Run "make" to regenerate code after modifying this file
|
||||
properties:
|
||||
args:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
command:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
domain:
|
||||
type: string
|
||||
host_ports:
|
||||
|
31
config/manager/config.yaml
Normal file
31
config/manager/config.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
# https://kubernetes.io/docs/concepts/configuration/configmap/
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: server-manager-config
|
||||
namespace: server-manager
|
||||
data:
|
||||
config.yaml: |
|
||||
domain_label: "ddns.acooldomain.co/hostname"
|
||||
default_domain: "acooldomain.co"
|
||||
browser:
|
||||
domain: games.acooldomain.co
|
||||
sub_path: /browsers
|
||||
auth_header: x-authentik-username
|
||||
cert_resolver: letsencrypt
|
||||
entrypoints:
|
||||
- websecure
|
||||
|
||||
additional_routes:
|
||||
- kind: Rule
|
||||
match: "Host(`games.acooldomain.co`) && PathPrefix(`/outpost.goauthentik.io/`)"
|
||||
priority: 15
|
||||
services:
|
||||
- kind: Service
|
||||
name: ak-outpost-traefik
|
||||
namespace: authentik
|
||||
port: 9000
|
||||
|
||||
middleware:
|
||||
name: authentik
|
||||
namespace: authentik
|
@@ -1,2 +1,3 @@
|
||||
resources:
|
||||
- config.yaml
|
||||
- manager.yaml
|
||||
|
@@ -1,32 +1,22 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
app.kubernetes.io/name: kubernetes-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: system
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: controller-manager
|
||||
namespace: system
|
||||
name: servermanager-manager
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
control-plane: servermanager-manager
|
||||
app.kubernetes.io/name: kubernetes-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
control-plane: servermanager-manager
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/default-container: manager
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
control-plane: servermanager-manager
|
||||
spec:
|
||||
# TODO(user): Uncomment the following code to configure the nodeAffinity expression
|
||||
# according to the platforms which are supported by your solution.
|
||||
@@ -48,6 +38,11 @@ spec:
|
||||
# operator: In
|
||||
# values:
|
||||
# - linux
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: server-manager-config
|
||||
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
# TODO(user): For common cases that do not require escalating privileges
|
||||
@@ -55,15 +50,18 @@ spec:
|
||||
# More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
|
||||
# Please uncomment the following code if your project does NOT have to work on old Kubernetes
|
||||
# versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ).
|
||||
# seccompProfile:
|
||||
# type: RuntimeDefault
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- command:
|
||||
- /manager
|
||||
args:
|
||||
- --leader-elect
|
||||
- --health-probe-bind-address=:8081
|
||||
image: controller:latest
|
||||
image: git.acooldomain.co/server-manager/kubernetes-operator:v0.0.8
|
||||
env:
|
||||
- name: CONFIG_PATH
|
||||
value: /etc/server-manager/config.yaml
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/server-manager
|
||||
name: manager
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -91,5 +89,5 @@ spec:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 64Mi
|
||||
serviceAccountName: controller-manager
|
||||
serviceAccountName: server-manager
|
||||
terminationGracePeriodSeconds: 10
|
||||
|
@@ -4,12 +4,12 @@ metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: kubernetes-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: manager-rolebinding
|
||||
name: server-manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: manager-role
|
||||
name: server-manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: controller-manager
|
||||
namespace: system
|
||||
name: server-manager
|
||||
namespace: server-manager
|
||||
|
@@ -4,5 +4,5 @@ metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: kubernetes-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: controller-manager
|
||||
namespace: system
|
||||
name: server-manager
|
||||
namespace: server-manager
|
||||
|
@@ -1,62 +0,0 @@
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: manager-role
|
||||
rules:
|
||||
- resources:
|
||||
- persistentvolumeclaims
|
||||
- services
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- resources:
|
||||
- pods
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- server-manager.acooldomain.co
|
||||
resources:
|
||||
- servermanagers
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- server-manager.acooldomain.co
|
||||
resources:
|
||||
- servermanagers/finalizers
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- server-manager.acooldomain.co
|
||||
resources:
|
||||
- servermanagers/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- traefik.io
|
||||
resources:
|
||||
- ingressroutes
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
32
config/samples/factorio_image-2.0.47.yaml
Normal file
32
config/samples/factorio_image-2.0.47.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
apiVersion: server-manager.acooldomain.co/v1alpha1
|
||||
kind: Image
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: kubernetes-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: factorio-2-0-47
|
||||
spec:
|
||||
location: git.acooldomain.co/server-manager/factorio:2.0.47
|
||||
name: factorio
|
||||
tag: 2.0.47
|
||||
working_dir: /opt/factorio
|
||||
volume: /opt/server
|
||||
command:
|
||||
- /opt/factorio/bin/x64/factorio
|
||||
- --port
|
||||
- "34197"
|
||||
args:
|
||||
- --start-server
|
||||
- saves/default.zip
|
||||
ports:
|
||||
- port: 34197
|
||||
protocol: TCP
|
||||
|
||||
init_script:
|
||||
image: alpine:latest
|
||||
command:
|
||||
- /bin/sh
|
||||
args:
|
||||
- /bin/sh
|
||||
- "-c"
|
||||
- "cp /opt/factorio /opt/server"
|
24
config/samples/minecraft_image-fabric-1.21.5.yaml
Normal file
24
config/samples/minecraft_image-fabric-1.21.5.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
apiVersion: server-manager.acooldomain.co/v1alpha1
|
||||
kind: Image
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: kubernetes-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: minecraft-fabric-1-21-5
|
||||
spec:
|
||||
location: git.acooldomain.co/server-manager/minecraft:fabric-1.21.5
|
||||
name: minecraft
|
||||
tag: fabric-1.21.5
|
||||
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"
|
24
config/samples/minecraft_image-paper-1.21.5.yaml
Normal file
24
config/samples/minecraft_image-paper-1.21.5.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
apiVersion: server-manager.acooldomain.co/v1alpha1
|
||||
kind: Image
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: kubernetes-operator
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
name: minecraft-paper-1-21-5
|
||||
spec:
|
||||
location: git.acooldomain.co/server-manager/minecraft:paper-1.21.5
|
||||
name: minecraft
|
||||
tag: paper-1.21.5
|
||||
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"
|
@@ -7,7 +7,7 @@ metadata:
|
||||
name: minecraft-paper-1-21-4
|
||||
spec:
|
||||
location: git.acooldomain.co/server-manager/minecraft:paper-1.21.4
|
||||
name: minecraft:paper-1.21.4
|
||||
name: minecraft
|
||||
tag: paper-1.21.4
|
||||
working_dir: /opt/server
|
||||
ports:
|
||||
|
@@ -157,6 +157,11 @@ func (r *ServerManagerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
||||
logging.Error(err, "Failed to get image")
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if len(s.Spec.Server.Ports) == 0 {
|
||||
s.Spec.Server.Ports = image.Spec.Ports
|
||||
err := r.Update(ctx, s)
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
serverPod := r.ServerPod(s, pvc, image)
|
||||
found := &corev1.Pod{}
|
||||
@@ -185,11 +190,27 @@ func (r *ServerManagerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
||||
s.Status.Server.Running = true
|
||||
statusChanged = true
|
||||
}
|
||||
if s.Status.Server.Command == nil {
|
||||
s.Status.Server.Command = serverPod.Spec.Containers[0].Command
|
||||
statusChanged = true
|
||||
}
|
||||
if s.Status.Server.Args == nil {
|
||||
s.Status.Server.Args = serverPod.Spec.Containers[0].Args
|
||||
statusChanged = true
|
||||
}
|
||||
default:
|
||||
if s.Status.Server.Running {
|
||||
s.Status.Server.Running = false
|
||||
statusChanged = true
|
||||
}
|
||||
if len(s.Status.Server.Args) != 0 {
|
||||
s.Status.Server.Args = nil
|
||||
statusChanged = true
|
||||
}
|
||||
if len(s.Status.Server.Command) != 0 {
|
||||
s.Status.Server.Command = nil
|
||||
statusChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +219,14 @@ func (r *ServerManagerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
||||
s.Status.Server.Running = false
|
||||
statusChanged = true
|
||||
}
|
||||
if len(s.Status.Server.Args) != 0 {
|
||||
s.Status.Server.Args = nil
|
||||
statusChanged = true
|
||||
}
|
||||
if len(s.Status.Server.Command) != 0 {
|
||||
s.Status.Server.Command = nil
|
||||
statusChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
logging.Info("verified pod")
|
||||
@@ -301,7 +330,7 @@ func (r *ServerManagerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
||||
}
|
||||
}
|
||||
}
|
||||
if errors.IsNotFound(err) && !s.Spec.Server.On {
|
||||
if errors.IsNotFound(err) && !s.Spec.Browser.On {
|
||||
if s.Status.Browser.Running {
|
||||
s.Status.Browser.Running = false
|
||||
statusChanged = true
|
||||
@@ -368,7 +397,7 @@ func (r *ServerManagerReconciler) GenerateBrowserUrl(s *servermanagerv1alpha1.Se
|
||||
}
|
||||
|
||||
func (r *ServerManagerReconciler) GenerateBrowserSubPath(s *servermanagerv1alpha1.ServerManager) string {
|
||||
if r.Config.Browser.SubPath == "" {
|
||||
if r.Config.Browser.SubPath != "" {
|
||||
return fmt.Sprintf("%s/%s/%s", r.Config.Browser.SubPath, s.Namespace, s.Name)
|
||||
} else {
|
||||
return fmt.Sprintf("/%s/%s", s.Namespace, s.Name)
|
||||
@@ -611,13 +640,10 @@ func (r *ServerManagerReconciler) ServerPvc(s *servermanagerv1alpha1.ServerManag
|
||||
|
||||
func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManager, pvc *corev1.PersistentVolumeClaim, image *servermanagerv1alpha1.Image) *corev1.Pod {
|
||||
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 serverPorts {
|
||||
ports[i] = corev1.ContainerPort{
|
||||
ContainerPort: port.Port,
|
||||
Protocol: port.Protocol,
|
||||
@@ -642,7 +668,7 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
|
||||
Name: "init",
|
||||
Image: image.Spec.InitScript.Image,
|
||||
ImagePullPolicy: corev1.PullIfNotPresent,
|
||||
Command: image.Spec.Command,
|
||||
Command: image.Spec.InitScript.Command,
|
||||
Args: image.Spec.InitScript.Args,
|
||||
VolumeMounts: []corev1.VolumeMount{
|
||||
{
|
||||
@@ -654,6 +680,11 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
|
||||
}
|
||||
}
|
||||
|
||||
volumePath := image.Spec.Volume
|
||||
if volumePath == "" {
|
||||
volumePath = image.Spec.WorkingDir
|
||||
}
|
||||
|
||||
pod := &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: s.Name,
|
||||
@@ -683,7 +714,7 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
|
||||
Ports: ports,
|
||||
VolumeMounts: []corev1.VolumeMount{{
|
||||
Name: "volume",
|
||||
MountPath: image.Spec.WorkingDir,
|
||||
MountPath: volumePath,
|
||||
}},
|
||||
Stdin: true,
|
||||
TTY: true,
|
||||
|
Reference in New Issue
Block a user