@@ -33,8 +33,224 @@ Prebundler.configure do |config|
3333 endpoint: 'https://us-east-1.linodeobjects.com',
3434 http_continue_timeout: 0
3535 ),
36- bucket: 'prebundler ',
36+ bucket: 'prebundler2 ',
3737 region: 'us-east-1'
3838 )
3939end
4040EOF
41+ prebundle install --jobs 2 --retry 3 --no-binstubs
42+
43+ # javascript deps, cxx flags because node-sass is a special snowflake
44+ CXXFLAGS=" --std=c++17" yarn install
45+
46+ # bootstrap app for use with kuby
47+ bundle exec bin/rails g kuby
48+ cat << EOF > kuby.rb
49+ class VendorPhase < Kuby::Docker::Layer
50+ def apply_to(dockerfile)
51+ dockerfile.copy('vendor/kuby-core', 'vendor/kuby-core')
52+ end
53+ end
54+
55+ require 'kuby/kind'
56+ require 'kuby/sidekiq'
57+ require 'kuby/prebundler'
58+ require 'active_support/core_ext'
59+ require 'active_support/encrypted_configuration'
60+
61+ # keep this in here to make sure RAILS_MASTER_KEY is being provided somehow
62+ app_creds = ActiveSupport::EncryptedConfiguration.new(
63+ config_path: File.join('config', 'credentials.yml.enc'),
64+ key_path: File.join('config', 'master.key'),
65+ env_key: 'RAILS_MASTER_KEY',
66+ raise_if_missing_key: true
67+ )
68+
69+ Kuby.define('Kubytest') do
70+ environment(:production) do
71+ docker do
72+ image_url 'localhost:5000/kubytest'
73+
74+ credentials do
75+ username "foobar"
76+ password "foobar"
77+ 78+ end
79+
80+ # have to insert after setup phase b/c prebundler replaces the existing bundler phase
81+ insert :vendor_phase, VendorPhase.new(environment), after: :setup_phase
82+ end
83+
84+ kubernetes do
85+ add_plugin :prebundler
86+
87+ add_plugin :rails_app do
88+ tls_enabled true
89+ hostname 'kubytest.io'
90+ end
91+
92+ configure_plugin(:cert_manager) do
93+ skip_tls_verify true
94+ server_url 'https://pebble.pebble:14000/dir'
95+ end
96+
97+ add_plugin :sidekiq do
98+ replicas 2
99+ end
100+
101+ provider :kind do
102+ use_kubernetes_version '${K8S_VERSION} '
103+ end
104+ end
105+ end
106+ end
107+ EOF
108+ cat << 'EOF ' > config/database.yml
109+ default: &default
110+ adapter: cockroachdb
111+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
112+ host: localhost
113+ development:
114+ <<: *default
115+ database: kubytest_development
116+ production:
117+ <<: *default
118+ database: kubytest_production
119+ EOF
120+ cat << 'EOF ' > config/routes.rb
121+ Rails.application.routes.draw do
122+ root to: 'home#index'
123+ end
124+ EOF
125+ cat << 'EOF ' > app/controllers/home_controller.rb
126+ class HomeController < ApplicationController
127+ def index
128+ end
129+ end
130+ EOF
131+ cat << 'EOF ' > app/models/widget.rb
132+ class Widget < ApplicationRecord
133+ end
134+ EOF
135+ mkdir -p app/sidekiq
136+ cat << 'EOF ' > app/sidekiq/widgets_job.rb
137+ class WidgetsJob
138+ include Sidekiq::Job
139+
140+ def perform(id)
141+ widget = Widget.find(id)
142+ widget.update(status: 'processed')
143+ end
144+ end
145+ EOF
146+ cat << 'EOF ' > config/initializers/sidekiq.rb
147+ if Rails.env.production?
148+ require 'kuby'
149+
150+ Kuby.load!
151+
152+ Sidekiq.configure_server do |config|
153+ config.redis = Kuby.environment.kubernetes.plugin(:sidekiq).connection_params
154+ end
155+
156+ Sidekiq.configure_client do |config|
157+ config.redis = Kuby.environment.kubernetes.plugin(:sidekiq).connection_params
158+ end
159+ end
160+ EOF
161+ mkdir -p db/migrate
162+ cat << 'EOF ' > db/migrate/20220423211801_create_widgets.rb
163+ class CreateWidgets < ActiveRecord::Migration[6.0]
164+ def change
165+ create_table :widgets do |t|
166+ t.string :status, default: 'pending'
167+ t.timestamps
168+ end
169+ end
170+ end
171+ EOF
172+ mkdir app/views/home/
173+ touch app/views/home/index.html.erb
174+
175+ # start docker registry (helps make sure pushes work)
176+ docker run -d -p 5000:5000 --name registry registry:2
177+
178+ # build and push
179+ GLI_DEBUG=true bundle exec kuby -e production build \
180+ -a PREBUNDLER_ACCESS_KEY_ID=${PREBUNDLER_ACCESS_KEY_ID} \
181+ -a PREBUNDLER_SECRET_ACCESS_KEY=${PREBUNDLER_SECRET_ACCESS_KEY}
182+ GLI_DEBUG=true bundle exec kuby -e production push
183+
184+ # setup cluster
185+ GLI_DEBUG=true bundle exec kuby -e production setup
186+ GLI_DEBUG=true bundle exec kuby -e production setup
187+
188+ # find kubectl executable
189+ kubectl=$( bundle show kubectl-rb) /vendor/kubectl
190+
191+ # export kubeconfig
192+ kind get kubeconfig --name kubytest > .kubeconfig
193+ export KUBECONFIG=.kubeconfig
194+
195+ # find ingress IP
196+ ingress_ip=$( $kubectl -n ingress-nginx get svc ingress-nginx-controller -o json | jq -r .spec.clusterIP)
197+
198+ # modification to the coredns config that resolves kubytest.io to the ingress IP
199+ corefile_mod=$( cat << END
200+ kubytest.io {
201+ hosts {
202+ $ingress_ip kubytest.io
203+ fallthrough
204+ }
205+ whoami
206+ }
207+ END
208+ )
209+
210+ # modify the coredns config (lives in Corefile) and restart the deployment
211+ $kubectl -n kube-system get configmap coredns -o json \
212+ | jq -r " .data.Corefile |= . + \" $corefile_mod \" " \
213+ | $kubectl apply -f -
214+ $kubectl -n kube-system rollout restart deployment coredns
215+ $kubectl -n kube-system wait --for=condition=available --timeout=120s deployment/coredns
216+
217+ # create pebble server (issues fake TLS certs) and get the root and intermediate certs
218+ $kubectl apply -f vendor/kuby-core/scripts/pebble.yaml
219+ $kubectl -n pebble wait --for=condition=available --timeout=30s deployment/pebble
220+ $kubectl -n pebble port-forward deployment/pebble 15000:15000 &
221+ sleep 2
222+ curl -f -vvv -ksS https://localhost:15000/intermediates/0 > pebble.intermediate.crt
223+ curl -f -vvv -ksS https://localhost:15000/roots/0 > pebble.root.crt
224+
225+ # deploy!
226+ GLI_DEBUG=true bundle exec kuby -e production deploy
227+
228+ # wait for pebble to issue the certificate
229+ while [[ " $( $kubectl -n kubytest-production get order -o json | jq -r ' .items[0].status.state' ) " != " valid" ]]; do
230+ echo " Waiting for certificate to be issued..."
231+ sleep 5
232+ done
233+
234+ # verify certificate chain
235+ $kubectl -n kubytest-production get secret kubytest-tls -o json \
236+ | jq -r ' .data["tls.crt"]' \
237+ | base64 -d - \
238+ | openssl verify -CAfile pebble.root.crt -untrusted pebble.intermediate.crt
239+
240+ # attempt to hit the app
241+ curl -vvv https://kubytest.io \
242+ --resolve kubytest.io:443:127.0.0.1 \
243+ --cacert pebble.root.crt \
244+ --fail \
245+ --connect-timeout 5 \
246+ --max-time 10 \
247+ --retry 5 \
248+ --retry-max-time 40
249+
250+ # insert job
251+ GLI_DEBUG=true bundle exec kuby -e production remote exec \
252+ " bundle exec rails runner 'w = Widget.create(status: \" pending\" ); WidgetsJob.perform_async(w.id)'"
253+
254+ GLI_DEBUG=true bundle exec kuby -e production remote exec \
255+ " bundle exec rails runner 'w = Widget.first; puts w.status'" \
256+ | grep ' processed'
0 commit comments