forked from cloudfoundry/docs-bosh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
create-release.html.md.erb
843 lines (579 loc) · 25.9 KB
/
create-release.html.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
---
title: Creating a Release
---
A release contains one or more pieces of software that work together.
For example, you could create a release of a service with three pieces:
two MySQL nodes and a dashboard app.
There are four fundamental elements in a release:
* **Jobs** describe pieces of the service or application you are releasing
* **Packages** provide source code and dependencies to jobs
* **Source** provides packages the non-binary files they need
* **Blobs** provide packages the binaries they need, other than binaries that
are checked into a source code repository
The following instructions use an example release that includes two jobs:
a web UI and a background worker.
The two jobs split up the functionality provided by single Ruby app,
`ardo_app`.
---
## <a id="prep"></a>Preparation ##
This section needs to be completed once.
Next, you iterate through Steps 1 through 6 until your dev release is
satisfactory.
Then you can do a final release.
### <a id="release-dir"></a>Create the release directory ###
To create the release directory, navigate into the workspace where you want the
release to be, and run:
`bosh init release <release_name>`
Use dashes in the release name.
Use underscores for all other filenames in the release.
View the release with `tree`:
<pre class="terminal">
$ tree .
.
├── blobs
├── config
│ └── blobs.yml
├── jobs
├── packages
└── src
5 directories, 1 file
</pre>
When deploying your release, BOSH places compiled code and other resources
in the `/var/vcap/` directory tree, which BOSH creates on the job VMs.
The four directories you just created, `jobs`, `packages`, `src`, and `blobs`,
appear on job VMs as `/var/vcap/jobs`, `/var/vcap/packages`, `/var/vcap/src`,
and `/var/vcap/blobs`, respectively.
### <a id="source"></a> Populate the src directory ###
Copy your source code into the `src` directory.
Alternatively, link your source code to the directory using a mechanism such as
a Git submodule or a Mercurial repo.
### <a id="strategy"></a> Choose a work strategy ###
Choose whether you want to work one Step at a time or one job at a time.
For releases with just a few jobs, going one Step at a time is probably easiest.
If you have a larger number of jobs, going one job at a time may be more efficient.
---
## <a id="job-skel"></a> Step 1: Create Job Skeletons ##
Navigate into the release directory.
For each job, create a job skeleton:
`bosh generate job <job_name>`
In our example, we run `bosh generate job` twice, once for the `web_ui` job,
and once for the `bg_worker` job.
View the job skeletons with `tree`:
<pre class="terminal">
$ tree .
.
├── blobs
├── config
│ └── blobs.yml
├── jobs
│ ├── bg_worker
│ │ ├── monit
│ │ ├── spec
│ │ └── templates
│ └── web_ui
│ ├── monit
│ ├── spec
│ └── templates
├── packages
└── src
9 directories, 5 files
</pre>
### <a id="control"></a> Create control scripts ###
Every job needs a way to start and stop.
You provide that by writing a control script and updating the `monit` file.
The control script:
* Includes a start command and a stop command.
* Is an ERb template stored in the `templates` directory for the relevant job.
For each job, create a control script that configures the job to store logs in `/var/vcap/sys/log/JOB_NAME`. Save this script as `ctl.erb` in the `templates` directory for its job.
The control script for the `web_ui` job looks like this:
<pre type="bash">
#!/bin/bash
RUN_DIR=/var/vcap/sys/run/web_ui
LOG_DIR=/var/vcap/sys/log/web_ui
PIDFILE=${RUN_DIR}/pid
case $1 in
start)
mkdir -p $RUN_DIR $LOG_DIR
chown -R vcap:vcap $RUN_DIR $LOG_DIR
echo $$ > $PIDFILE
cd /var/vcap/packages/web_ui
export PATH=/var/vcap/packages/ruby_1.9.3/bin:$PATH
exec /var/vcap/packages/ruby_1.9.3/bin/bundle exec \
rackup -p <%%= properties.web_ui.port %> \
>> $LOG_DIR/web_ui.stdout.log \
2>> $LOG_DIR/web_ui.stderr.log
;;
stop)
kill -9 `cat $PIDFILE`
rm -f $PIDFILE
;;
*)
echo "Usage: ctl {start|stop}" ;;
esac
</pre>
If your release needs templates other than the control script, create them now.
### <a id="monit"></a> Update monit files ###
The `monit` file:
* Specifies the process ID (pid) file for the job
* References each command provided by the templates for the job
* Specifies that the job belongs to the `vcap` group
On a deployed release, a BOSH Agent runs on each job VM.
BOSH communicates with the Agent, which in turn executes commands in the
control script.
The Agent does this using open source process monitoring software called
[Monit](http://mmonit.com/monit/).
The `monit` file for the `web_ui` job looks like this:
<pre type="terminal">
check process web_ui
with pidfile /var/vcap/sys/run/web_ui/pid
start program "/var/vcap/jobs/web_ui/bin/ctl start"
stop program "/var/vcap/jobs/web_ui/bin/ctl stop"
group vcap
</pre>
Update the `monit` file for each of your jobs.
Use `/var/vcap` paths as shown in the example.
<p class="note"><strong>Note</strong>: BOSH requires a <code>monit</code> file for each job in a release. When developing a release, you can use an empty <code>monit</code> file to meet this requirement without having to first create a control script.</p>
### <a id="job-specs"></a> Update job specs ###
At compile time, BOSH transforms templates into files, which it then replicates
on the job VMs.
The template names and file paths are among the metadata for each job that
resides in the job `spec` file.
In the job `spec` file, the `templates` block contains key/value pairs where:
* Each key is template name
* Each value is the path to the corresponding file on a job VM
The file paths that you provide for templates are relative to
the `/var/vcap/jobs/<job_name>` directory on the VM.
For example, `bin/ctl` becomes `/var/vcap/jobs/<job_name>/bin/ctl` on the job VM.
Using `bin` as the directory where these files go is a convention.
The `templates` block of the updated `spec` files for the example jobs look
like this:
~~~yaml
templates:
ctl.erb: bin/ctl
~~~
For each job, update the `spec` file with template names.
### <a id="commit-one"></a> Commit ###
You have now created one or more job skeletons; this is a good time to commit.
If you used the `--git` option with `bosh init release` (as recommended), the
correct `.gitignore` file has been automatically created for you.
---
## <a id="graph"></a> Step 2: Make Dependency Graphs ##
There are two kinds of dependencies in a BOSH release:
* The **runtime dependency**, where a job depends on a package at runtime.
For example, the `web_ui` job depends on Ruby.
* The **compile-time dependency**, where a package depends on another package at
compile time.
For example, Ruby depends on the YAML library.
Three rules govern these dependencies:
* Jobs never depend on other jobs.
* Jobs can depend on packages.
* Packages can depend on other packages.
### <a id="build-graph"> </a>Building the Dependency Graph ###
Create a dependency graph to clarify your understanding of the
dependencies between the jobs and packages in your release.
#### <a id="runtime"> </a>Identify runtime dependencies ####
Whenever a control script or other template cites a package name, the job
that the template belongs to depends on the cited package at runtime.
For each job, find all the cases where your control scripts cite packages.
Add these runtime dependencies to your dependency graph.
In our example, this line in both of our `ctl.erb` scripts cites `ardo_app`:
~~~
cd /var/vcap/packages/ardo_app
~~~
This line cites Ruby:
~~~
exec /var/vcap/packages/ruby_1.9.3/bin/bundle exec
~~~
This means that both the `web-ui` and `bg_worker` jobs have runtime
dependencies on both the `ardo_app` and `ruby_1.9.3` packages.
We add these four runtime dependencies to our example dependency graph.
#### <a id="compile-time"> </a>Identify compile-time dependencies ####
Use your knowledge about the runtime dependencies you have already noted.
Consider the packages you have identified as dependencies.
Do any of them depend on other packages in turn?
Whenever a package depends on another package, that is a compile-time
dependency.
For each job, add the compile-time dependencies to your dependency graph.
If you miss a dependency, BOSH lets you know later, when you try to deploy.
In our example, we already noted a runtime dependency on Ruby 1.9.3.
We now ask ourselves whether Ruby 1.9.3 itself has any dependencies.
The answer is yes, it depends on libyaml 0.1.4.
We add this compile-time dependency to our example dependency graph.
#### <a id="dep-graph-example"> </a>The complete example dependency graph ####
The complete dependency graph for `ardo-release` looks like this:
<%= image_tag("./images/dep-graph.png") %>
For a large or complicated release, consider making more than one dependency
graph.
## <a id="pkg-skeletons"></a> Step 3: Create Package Skeletons ##
Packages give BOSH the information needed to prepare the binaries and
dependencies for your jobs.
Create package skeletons starting from the bottom of your dependency graph.
`bosh generate package <dependency_name>`
In our example, we run this command three times.
Starting from the bottom of the dependency graph,
we run it for `libyaml_0.1.4`, `ruby_1.9.3`, and `ardo_app`.
View the package skeletons with `tree`:
<pre class="terminal">
$ tree packages
packages
├── ardo_app
│ ├── packaging
│ ├── pre_packaging
│ └── spec
├── libyaml_0.1.4
│ ├── packaging
│ ├── pre_packaging
│ └── spec
└── ruby_1.9.3
├── packaging
├── pre_packaging
└── spec
3 directories, 9 files
</pre>
Putting each dependency in a separate package provides maximum reusability
along with a clear, modular structure. This is not mandatory; what packages
to create is a matter of preference. You could even opt to put all the
dependencies together in a single package, though that is not recommended.
<p class="note"><strong>Note</strong>: Use of the <code>pre_packaging</code> file is not recommended, and is not discussed in this tutorial.</p>
### <a id="update-pkging-specs"></a> Update packaging specs ###
Within each package directory, there is a `spec` file which states:
* The package name
* The package's dependencies
* The location where BOSH can find the binaries and other files that the package needs at compile time
Use your dependency graph to determine which dependencies belong in each spec.
Developer preferences and style play a role here.
Consider our example: the spec for Ruby lists `rubygems` and `bundler` as dependencies along
with Ruby itself.
Some Ruby developers would do it this way; others would not.
To maximize portability of your release across different versions of stemcells,
never depend on the presence of libraries or other software on stemcells.
To describe binary locations in the `files` block of the spec:
* Find the official site for the binary in question.
For example, Ruby might be at `http://cache.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p484.tar.gz`.
* Download the binary from the official location and make sure the file hash matches.
* Record the binary name including version number, with a slash and the binary
filename concatenated to it.
It's a good idea to cite the official URL in a comment, in the same line.
BOSH interprets the locations you record in the `files` section as being
either in the `src` directory or in the `blobs` directory.
(BOSH looks in `src` first.)
When you add the actual blobs to a blobstore (see the next section),
BOSH populates the `blobs` directory with the correct information.
For packages that depend on their own source code, use the globbing pattern
`<package_name>/**/*` to deep-traverse the directory in `src` where
the source code should reside.
Update the spec for each package.
Refer to the example specs below for guidance.
#### <a id="pkg-spec-libyaml"></a> Example libyaml package spec ####
~~~yaml
---
name: libyaml_0.1.4
dependencies: []
files:
- libyaml_0.1.4/yaml-0.1.4.tar.gz # From http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
~~~
#### <a id="pkg-spec-ruby"></a> Example Ruby package spec ####
~~~yaml
---
name: ruby_1.9.3
dependencies:
- libyaml_0.1.4
files:
- ruby_1.9.3/ruby-1.9.3-p484.tar.gz # http://cache.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p484.tar.gz
- ruby_1.9.3/rubygems-1.8.24.tgz # http://rubyforge.org/frs/download.php/76073/rubygems-1.8.24.tgz
- ruby_1.9.3/bundler-1.2.1.gem # https://rubygems.org/downloads/bundler-1.2.1.gem
~~~
#### <a id="pkg-spec-ardo"></a> Example ardo_app package spec ####
~~~yaml
---
name: ardo_web
dependencies:
- ruby_1.9.3
files:
- ardo_web/**/*
~~~
### <a id="pkg-scripts"></a> Create packaging scripts ###
At compile time, BOSH takes the source files referenced in the package specs,
and renders them into the executable binaries and scripts that your deployed
jobs need.
You write packaging scripts to instruct BOSH how to do this.
The instructions may involve some combination of copying, compilation, and
related procedures.
For example:
* For a Ruby app like `ardo_app`, BOSH must copy source files and install Ruby
gems.
* For Ruby itself, BOSH must compile source code into a binary.
* For a Python app, BOSH must copy source files and install Python eggs.
BOSH relies on you to write packaging scripts that perform the correct operation.
Adhere to these principles when writing packaging scripts:
* Use your dependency graph to determine which dependencies belong in each
packaging script.
* Begin each script with a `set -e -x` line.
This aids debugging at compile time by causing the script to exit immediately
if a command exits with a non-zero exit code.
* Ensure that any copying, installing or compiling delivers resulting code to
the install target directory (represented as the `BOSH_INSTALL_TARGET`
environment variable). For `make` commands, use `configure` or its equivalent
to accomplish this.
* Be aware that BOSH ensures that dependencies cited in the `dependencies`
block of package `spec` files are available to the deployed binary.
For example, in the `spec` file for the Ruby package, we cite libyaml as a
dependency.
This ensures that on the compilation VMs, the packaging script for Ruby has
access to the compiled libyaml package.
If the instructions you provide in the packaging scripts fail to deliver compiled
code to `BOSH_INSTALL_TARGET`, the job cannot function because the VM has no
way to find the code to run.
This failure scenario can happen if, for example,
you use a `make` command that delivers compiled code to some standard location
by default.
You can fix the problem by configuring `make` to compile into
`BOSH_INSTALL_TARGET`.
See how this is done in the example packaging scripts.
Like control scripts, writing packaging scripts is one of the heavier tasks
entailed in creating a release.
Write your packaging scripts now.
Refer to the examples below for guidance.
#### <a id="pkg-script-libyaml"></a> Example libyaml packaging script ####
~~~
set -e -x
tar xzf libyaml_0.1.4/yaml-0.1.4.tar.gz
pushd yaml-0.1.4
./configure --prefix=${BOSH_INSTALL_TARGET}
make
make install
popd
~~~
#### <a id="pkg-script-ruby"></a> Example Ruby packaging script ####
~~~
set -e -x
tar xzf ruby_1.9.3/ruby-1.9.3-p484.tar.gz
pushd ruby-1.9.3-p484
./configure \
--prefix=${BOSH_INSTALL_TARGET} \
--disable-install-doc \
--with-opt-dir=/var/vcap/packages/libyaml_0.1.4
make
make install
popd
tar zxvf ruby_1.9.3/rubygems-1.8.24.tgz
pushd rubygems-1.8.24
${BOSH_INSTALL_TARGET}/bin/ruby setup.rb
popd
${BOSH_INSTALL_TARGET}/bin/gem install ruby_1.9.3/bundler-1.2.1.gem --no-ri --no-rdoc
~~~
#### <a id="pkg-script-ardo"></a> Example ardo_app packaging script ####
~~~
set -e -x
cp -a ardo_app/* ${BOSH_INSTALL_TARGET}
cd ${BOSH_INSTALL_TARGET}
/var/vcap/packages/ruby_1.9.3/bin/bundle install \
--local \
--deployment \
--without development test
~~~
### <a id="update-job-specs-with-deps"></a> Update job specs with dependencies ###
The dependency graph reveals runtime dependencies that
need to be added to the `packages` block of the job spec.
Edit the job specs to include these dependencies.
In our example, the dependency graph shows that `web_ui` job depends on
`ardo_app` and `ruby_1.9.3`:
~~~yaml
packages:
- ardo_app
- ruby_1.9.3
~~~
---
## <a id="blobs"></a> Step 4: Add Blobs ##
When creating a release, you likely use a source code repository.
But releases often use tar files or other binaries, also known as blobs.
Checking blobs into a repository is problematic if your repository
unsuited to dealing with large binaries (as is true of Git, for example).
BOSH lets you avoid checking blobs into a repository by doing the following:
* For dev releases, use local copies of blobs.
* For a final release, upload blobs to a blobstore, and direct BOSH to obtain the blobs from there.
### <a id="config-blobstore"></a> Configure a blobstore ###
In the `config` directory, you record the information BOSH needs about the
blobstore:
* The `final.yml` file names the blobstore and declares its type, which is either `local`
or one of several other types that specify blobstore providers.
* The `private.yml` file specifies the blobstore path, along with a secret.
`private.yml` contains keys for accessing the blobstore and should not be
checked into a repository.
(If you used the `--git` option when running `bosh init release` at the beginning
of this tutorial, `private.yml` is automatically `gitignored`.)
The `config` directory also contains two files whose content is automatically
generated: the `blobs.yml` file and the `dev.yml` file.
Adapt the examples below to fit the specifics of your release.
Our example release uses the `local` type blobstore because otherwise it would
be necessary to explain how to configure a public blobstore such as
Amazon S3, which is too large a topic for this context.
The `local` type blobstore is suitable for learning but the resulting release
cannot be shared.
For that reason, you should configure a non-local, publicly available blobstore
for releases that you intend to share.
Normally, the blobstore you choose when you begin working on a release is used
for all subsequent versions of the release.
Changing the blobstore that a release uses is beyond the scope of this tutorial.
Example `final.yml`:
~~~yaml
---
blobstore:
provider: local
options:
blobstore_path: /tmp/ardo-blobs
final_name: ardo_blobstore
~~~
Example `private.yml`:
~~~yaml
---
blobstore_secret: 'does-not-matter'
blobstore:
local:
blobstore_path: /tmp/ardo-blobs
~~~
If you have a `private.yml` file:
* **Required**: Include the `blobstore_path` in the `private.yml` file.
* **Optional**: Include the `blobstore_path` in the `final.yml` file. Doing so allows you to `gitignore` the `private.yml` file but still allow the release to be downloaded and used on other systems.
<p class="note"><strong>Note</strong>: The <code>blobstore_secret</code> is required for the <code>local</code> type blobstore.
This is true even though the <code>blobstore_secret</code> line is deprecated and its
content does not matter.
There is never <code>blobstore_secret</code> line for blobstores of types other than
<code>local</code>.</p>
### <a id="inform"></a> Inform BOSH where blobs are ###
In the package `spec` file, the `files` block lists any binaries you downloaded,
along with the URLs from which you downloaded them.
(This assumes that you followed the directions in the [Update package specs](#update-pkging-specs) section.)
Those files are blobs, and now you need the paths to the downloaded blobs on
your local system.
In our example, the `spec` file for the `libyaml_0.1.4` package includes the line:
~~~yaml
files:
- libyaml_0.1.4/yaml-0.1.4.tar.gz # From http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
~~~
If you downloaded the blob, its local path might be:
`~/Downloads/yaml-0.1.4.tar.gz`
Go through all your packages and make a list of local paths to the blobs you downloaded.
Now you are ready to inform BOSH about these blobs.
For each blob, run:
`bosh add blob <path_to_blob_on_local_system> <package_name>`
The `bosh add blob` command adds a local blob to the collection your release
recognizes as BOSH blobs.
The usage shown above is a blend of requirement and convention.
It works like this:
* For the first argument, you provide the path to the blob on your local system
* For the second argument, you provide a destination within the `blobs` directory
in your release
* BOSH goes into the `blobs` directory and creates a subdirectory with
the name of the package that the local blob represents
* In the new subdirectory, BOSH creates a symbolic link to a copy of the blob
which BOSH makes in a hidden directory
Using the package name as the second argument of the `bosh add blobs` command
is recommended because it produces a cleanly-organized blobs directory.
Later, when you upload blobs for a final release, BOSH uses the hidden directory
as a staging area.
### <a id="no-upload"></a> Do not upload blobs for a dev release ###
Once you have uploaded blobs to a non-local blobstore, those blobs may become
essential to some other developer.
For this reason, uploading a blob and then removing it is considered poor practice.
When creating dev releases, do not run `bosh upload blobs`.
(You only run it when you do a final release.)
---
## <a id="create-props"></a> Step 5: Create Job Properties ##
If your service needs to be configurable at deployment time,
you create the desired inputs or controls and specify them in the release.
Each input is a _property_ that belongs to a particular job.
Creating properties requires three steps:
1. Define properties and defaults in the `properties` block of
the job spec.
1. Use the property lookup helper `p()` to reference properties in
relevant templates.
For example, a start command can take a property as an argument,
using the property lookup helper:
<%%= p('<job_name>.<property_name>') %>
1. Specify the property in the [deployment manifest](./deployment-manifest.html#properties).
Adapt the example below to create any properties your release needs now.
In our example, we want the port that the web UI listens on to be a
configurable property.
We edit the spec for the web UI job to look like this:
~~~yaml
properties:
web_ui.port:
description: Port that web_ui app listens on
default: 80
~~~
---
## <a id="dev-release"></a> Step 6: Create a Dev Release ##
All the elements needed to create a dev release should now be in place.
### <a id="dev-release-release"></a> Release ###
For the dev release, use the `--force` option with the `bosh create release`
command.
This forces BOSH to use the local copies of our blobs.
Without the `--force` option, BOSH requires blobs to be uploaded before you
run `bosh create release`.
For a final release, we upload blobs, but not for a dev release.
Create the dev release:
`bosh create release --force`
BOSH prompts for a release name, and assigns a dot-number version to the release.
### <a id="dev-release-deploy"></a> Deploy the Dev Release ###
Deploying the release requires three or more steps, depending on whether
BOSH is targeting the desired Director, and whether BOSH is already pointing
to a release.
See what director BOSH is targeting:
`bosh target`
Target a director:
`bosh target <director_url>`
See what releases are available:
`bosh releases`
If BOSH is already pointing to a release, edit the BOSH deployment manifest.
Otherwise, create a manifest. See [BOSH Deployment Manifest](./deployment-manifest.html) for more information.
Upload the new dev release.
`bosh upload release`
Assuming you are in the release directory, no path is needed with the above command.
Deploy:
`bosh deploy`
See [Deploying Distributed Software with BOSH](./deploy-with-bosh.html) for more
about deployment.
### <a id="dev-release-test"></a> Test the Dev Release ###
What tests to run depends on the software you are releasing.
Start by opening a separate terminal, logging in on the job VM, and observing
logging output as you test your release.
If your release fails tests, follow this pattern.
* Fix the code.
* Do a new dev release.
* Run `bosh deploy` to see whether the new release deploys successfully.
Using `bosh deploy --recreate` can provide a clearer picture because with that option,
BOSH deploys all the VMs from scratch.
---
## <a id="final-release"></a> Create a Final Release ##
Only proceed to this step if your latest dev release passes all tests.
### <a id="upload-blobs"></a> Upload blobs ###
When you use the `bosh create release --force` command to create them, dev
releases depend on locally-stored blobs.
To do a final release, you must upload blobs first.
If files that you need to keep private are uploaded to a public blobstore,
there is no satisfactory way to undo the mistake.
To avoid this situation, complete the following steps immediately before
you upload blobs:
1. Run `bosh blobs` to see the list of blobs BOSH is prepared to upload
1. Proofread the list of blobs displayed by the command
1. The list should include only the blobs you need for the final release
1. If the list includes any files that should not be uploaded, find and delete
the symbolic links to them in the `blobs` directory
To upload your blobs, run:
`bosh upload blobs`
### <a id="final-commit-two"></a> Commit ###
The `bosh upload blobs` command has now populated the `blobs.yml` file
in the `config` directory with metadata for uploaded blobs.
This is a good reason to commit.
### <a id="final-release-release"></a> Release ###
Run:
`bosh create release --final`
BOSH prompts you for a release name, and assigns a whole-number version to the release.
This is a good time to push your code to a shared repository to give others access to
your final release.
### <a id="final-release-commit"></a> Commit ###
Do one more commit before you deploy!
### <a id="final-release-deploy"></a> Deploy the Final Release ###
Run:
`bosh deploy`